I'm thinking of writing a Proxy Server. When I specify and activate the port using the TIdHTTPProxyServer component, the proxy server works properly. It's okay so far, but I can't password it and I can't open an IPv6 proxy. It's just an IPv4 proxy. I couldn't find much documentation on this.
I can't password it
TIdHTTPProxyServer does not currently implement any authentication of its own.
HTTP authentication between the client and target server is handled transparently between the two of them, TIdHTTPProxyServer is not involved in that process.
If you want to password-protect the proxy itself, you will have to manually handle authentication in the proxy's OnHTTPBeforeCommand event. Check the client's request headers (in the event's AContext.Headers property) for a Proxy-Authorization header, and if it is not present, or its credentials fail, then manually send the client (via the AContext.Connection property) an HTTP 407 response containing an appropriate Proxy-Authenticate header, and then raise an exception (or disconnect the AContext.Connection) to stop processing the current proxy request.
I can't open an IPv6 proxy. It's just an IPv4 proxy.
TIdHTTPProxyServer can handle both IPv4 and IPv6, but it will require some manual setup.
Whichever IP version Indy is compiled for by default is specified in the global ID_DEFAULT_IP_VERSION constant in Indy's IdGlobal unit (it is set to IPv4, unless Indy is compiled with IdIPv6 defined in IdCompilerDefines.inc).
Listening IP/port pairs can be configured in the proxy's Bindings collection. You can specify an IPVersion for each binding. The IPVersion is set to ID_DEFAULT_IP_VERSION by default.
If you don't specify any Bindings entries, the proxy's DefaultPort property is used instead. The proxy will then open either 1 or 2 listening ports, depending on platform and OS capabilities. If 1 port is opened, it will use ID_DEFAULT_IP_VERSION. If 2 ports are opened, 1 will be IPv4 and 1 will be IPv6.
So, if you want control over the setup of the listening IP/ports, don't leave the Bindings empty.
Once a client has connected to a listening port, the TIdHTTPProxyServerContext.OutboundClient object that is used to connect to the next HTTP server will use ID_DEFAULT_IP_VERSION by default. You can override this in the proxy's OnHTTPBeforeCommand event, by casting the event's AContext.OutboundClient property to TIdTCPClient and then setting its IPVersion property.
Related
Previously the URL I needed to check was http and I used TidTCPClient to emulate the http protocol to determine the file at the web server existed. Now they have switched to https and I don't know how to do it.
Can I use TIdHTTP with the TIdSSLIOHandlerSocketOpenSSL hander, and then some Indy function to only determine the resource exists? I have OpenSSL installed.
Your existing TIdTCPClient code should continue to work if you simply assign a TIdSSLIOHandlerSocketOpenSSL to the client's IOHandler, change the client's Port to 443, and set the IOHandler's PassThrough to False. HTTPS is just HTTP over an SSL/TLS connection, it doesn't change HTTP itself.
But to answer your question, yes, you can switch to TIdHTTP if you want to. You can use the HTTP HEAD command (the TIdHTTP.Head() method) to check if a URL is valid without having to download a full resource.
In C++ (I didn't include code because this is more of a protocol understanding matter) I am creating a SOCKS5 server and had a few questions because the client terminates the connection after I send it the approved message. In the RFC it says BND.ADDR and BND.PORT are used for: RFC 1928
o BND.ADDR server bound address
o BND.PORT server bound
port in network octet order`
In the reply to a CONNECT, BND.PORT contains the port number that the
server assigned to connect to the target host, while BND.ADDR
contains the associated IP address.
Here are my questions,
What is BND.PORT and what should I specify for it?.
What does it mean by "server assigned to connect to the target host" Is target host the "Client"?
I've read the RFC front to back like 5 times and I have yet to understand it, can someone go into more detail about the BND.PORT and what it means?
I was sniffing around in Wireshark and I found that BND.PORT was different for each request made. (I am not sure what port to enter because everything I tried resulted in Proxifer (The socks client) says "The server gave an unexpected replay - Connection terminated"
Wireshark connection hex-dump from an actual SOCKS5 server (not mine):
Just to make sure we're on the same page... This is the relationship between client, server and host. Notice that the client and host can't talk to each other directly.
CLIENT <-> SERVER <-> HOST
What does it mean by "server assigned to connect to the target host" Is target host the "Client"?
No. The "host" is the device the client is trying to connect to via the SOCKS5 server. The "client" is on the other side of the SOCKS5 server, furthest away from the host.
What is BND.PORT and what should I specify for it?.
BND.PORT is the source port of packets leaving the SOCKS5 server, bound for a host. You have no control over what port the server chooses. Think about it. Where does a host see packets coming from? It certainly isn't the client. From the perspective of the host, packets are all coming from the server, it doesn't know about the client. Additionally the BND.ADDR is the IP of the server.
What I've said is true under the condition that CONNECT is being used. I have no experience with BIND or UDP ASSOCIATE yet.
I am not good with delphi yet, but based on some examples I have managed to create simple http server with no more than 10 users.
There are 2 main problems I don't know how to solve yet.
proper way to authenticate, manage users - sessions
main problem, connection must be secure, so SSL encryption is needed, how to implement it?
Any example I found in relation with idhttpserver and openssl, was not quite complete or with older version of Indy.
I am currently working with Delphi XE2 with Indy 10 components.
proper way to authenticate, manage users - sessions
TIdHTTPServer manages HTTP sessions for you if you set the TIdHTTPServer.SessionState property is true (it is false by default). TIdHTTPServer uses cookies for session management, so your clients need to have cookies enabled.
Authentication has to be performed manually, but how you do that depends on whether your clients are using HTTP-based or HTML-based authentication.
For HTTP authentication, there are ARequestInfo.UserName and ARequestInfo.Password properties available. If not valid, send an appropriate 401 response back to the client (if you set the AResponseInfo.AuthRealm property to a non-blank string, TIdHTTPServer will send a 401 response for you). By default, TIdHTTPServer only supports BASIC authentication. If you want to support other authentication schemes, you will have to use the TIdHTTPServer.OnParseAuthentication event, and send the 401 reply manually so you can send back appropriate WWW-Authenticate headers. Either way, if the client is validated, you can use HTTP sessions to keep the client logged in between requests. The AResponseInfo.Session and AResponseInfo.Session properties point at the current session. If TIdHTTPServer.AutoStartSession is true (it is false by default), TIdHTTPServer creates new sessions automatically. Otherwise, you can call TIdHTTPServer.CreateSession() yourself when needed. TIdHTTPSession has a Content property that you can store session-specific data in. Or you can derive a new class from TIdHTTPSession and then use the TIdHTTPServer.OnCreateSession event to create instances of that class.
For HTML authentication, you have two choices, depending on how you configure your HTML:
if your HTML <form> tag does not have an enctype attribute, or it is set to application/x-www-webform-urlencoded, TIdHTTPServer will store the raw webform data in the ARequestInfo.FormParams property, and if TIdHTTPServer.ParseParams is true (which it is by default), the data will also be parsed into the ARequestInfo.Params property for you.
if your HTML <form> tag has an enctype attribute set to multipart/form-data, you will have to parse the content of the ARequestInfo.PostStream manually, as TIdHTTPServer does not yet parse that data for you (examples have been posted many times before on many different forums on how to parse that data manually using Indy's TIdMessageDecoderMIME class). By default, ARequestInfo.PostStream points at a TMemoryStream object. You can use the TIdHTTPServer.OnCreatePostStream event to create an instance of a different TStream-derived class, if desired.
main problem, connection must be secure, so SSL encryption is needed, how to implement it?
Before activating the server:
assign a TIdServerIOHandlerSSLBase-derived component, such as TIdServerIOHandlerSSLOpenSSL, to the TIdHTTPServer.IOHandler property and configure it as needed (certificate, peer validation, SSL version(s), etc). In the case of OpenSSL, you will have to deploy the 2 OpenSSL library binaries libeay32.dll and ssleay32.dll (or non-Windows platform equivalents) with your app if they are not already pre-installed on the target OS, or if you want to ensure your app uses a specific version of OpenSSL. At this time, OpenSSL is the only encryption that Indy supports natively, but there are third-party solutions available that are compatible with Indy, such as EldoS SecureBlackbox.
fill in the TIdHTTPServer.Binding property with a binding for your desired HTTPS port (443 is the default HTTPS port). Typically you should create 2 bindings, one for HTTP port 80 and one for HTTPS port 443. Inside your OnCommand... handlers, if you receive a request that requires SSL/TLS encryption, you can check the port that the request was made on (AContext.Binding.Port) and if not HTTPS then redirect (AResponseInfo.Redirect()) the client to retry the request on the HTTPS port.
assign a handler to the TIdHTTPServer.OnQuerySSLPort event and have it set its VUseSSL parameter to True when its APort parameter matches your HTTPS port. UPDATE starting with SVN rev 5461, an OnQuerySSLPort handler is no longer needed if your only HTTPS port is 443.
I am working with D5 ( thats a fact ). I have Indy9 installed.
I'm trying to receive data of IdMappedPortTCP on port 8041 (SSL) and redirect the data to a Tserversocket on port 8040. So I will have support of SSL over Tserversocket.
I use the following code:
var
masterdir:String;
begin
masterdir:=Extractfilepath(paramstr(0));
IdMappedPortTCP1.Active:=false;
datamodule2.IdMappedPortTCP1.MappedHost:='192.168.0.3';
datamodule2.IdMappedPortTCP1.MappedPort:=8041;
datamodule2.IdMappedPortTCP1.DefaultPort:=8040;
IdServerIOHandlerSSL1.SSLOptions.RootCertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.CertFile:=masterdir+'mycert.pem';
IdServerIOHandlerSSL1.SSLOptions.KeyFile:=masterdir+'key.pem';
IdMappedPortTCP1.IOHandler:=IdServerIOHandlerSSL1;
IdMappedPortTCP1.Active:=true;
end;
If I don't use SSL everything is fine. But when I use SSL teh request never comes to the port 8040 encrypted and I need it not encrypted so I can proccess it.
It is not clear from your description whether TServerSocket is using SSL on port 8040 or not. It makes a big difference in how you set up TIdMappedPortTCP. However, from your description, you have the MappedPort and DefaultPort property assignments backwards, at least. DefaultPort is the port that TIdMappedPortTCP listens on, so it should be 8041. MappedPort is the port that TIdMappedPortTCP connects to, so it should be 8040.
It is not common to have unencrypted and encrypted connections on the same port. Most protocols use separate ports. Is that the case here? Is port 8040 unencrypted, and port 8041 encrypted?
If you want TIdMappedPortTCP to accept encrypted and unencrypted clients on separate ports, you need to add 2 entries to the TIdMappedPortTCP.Bindings collection, one for each port, and not use the DefaultPort property at all. In the TIdMappedPortTCP.OnConnect event, you can detect which port the client connected to, and then configure the AThread.OutboundClient accordingly before it connects to TServerSocket.
It is not wise to have unencrypted and encrypted clients connect to the same port. In that scenario, you have to sniff the first few bytes to know if the client is sending an SSL handshake or not, and then act accordingly. It is easier to just use separate ports instead. However, some protocols do allow a client to connect to an unencrypted port and then send a command to activate encryption when needed. In that scenario, you would only need 1 port in TIdMappedPortTCP, so you can either define 1 Binding or use DefaultPort.
TIdMappedPortTCP is primarily intended to be a straight passthrough of raw bytes back and forth between the client and the target server. If TServerSocket is using SSL and you want the client to talk to TServerSocket using SSL properly, you should not be using TIdServerIOHandlerSSL at all. Let TIdMappedPortTCP pass the client's raw encrypted data as-is to TServerSocket, and vice versa. They should establish a secure session with each other, not with you. This is especially important if either one of them performs peer identity validation.
If you need to process encrypted data that is being exchanged between the client and TServerSocket, you have to decrypt and re-encrypt the data as it passes through TIdMappedPortTCP (which means you are acting as a man-in-the-middle attacker, which peer validation is meant to prevent). To do that, you have to establish separate SSL sessions between the client and TIdMappedPortTCP, and between TIdMappedPortTCP and TServerSocket. Assigning a TIdServerIOHandlerSSL to TIdMappedPortTCP only facilitates the session with the client. You have to manually setup a session with TServerSocket. To do that, you have to manually assign a new TIdSSLIOHandlerSocket object to the AThread.OutboundClient.IOHandler property in the OnConnect event. TIdMappedPortTCP will not handle that for you.
If, however, TServerSocket is not using SSL, and you are using TIdMappedPortTCP as an SSL gateway into TServerSocket, then you can skip the OutboundClient.IOHandler assignment, since you would only need 1 SSL session, between TIdMappedPortTCP and the client.
Now, with that said, there are some problems in Indy 9. The TIdSSLIOHandlerOpenSSL.PassThrough property is False by default (thus assuming encryption is initially active), and TIdServerIOHandlerSSL assumes that every accepted client connection is using SSL, even if it really is not. If an unencrypted client connects to TIdMappedPortTCP with TIdServerIOHandlerSSL assigned, the client will not be handled correctly. These issues were fixed in Indy 10. But in Indy 9, you will not be able to handle encrypted and unencrypted clients in the same TIdMappedPortTCP component. If you are only dealing with encrypted clients though, you won't run into a problem. Otherwise, create 2 TIdMappedPortTCP components, one listening on an unencrypted port, the other listening on an encrypted port. They can share the same event handlers. If needed, you can use the AThread.Connection.Socket.Binding.Port property to know which port the client is connected to.
How can i connect to a server through a http proxy server in delphi?
What about SOCKS5 proxy?
Google doesn't have any suggestion!
If you're using Indy (highly recommended), then try using a TIdConnectThroughHttpProxy object from the IdConnectThroughHttpProxy unit. It's a descendant of TIdIOHandler, so connect an instance of that class to your client object's IOHandler property. To connect through a Socks server instead, use TIdSocksInfo, in IdSocks.
If you're set on doing it manually, without the aid of a protocol library like Indy, then connect your TTcpClient object to the proxy server's address instead of the real destination, and then send your commands there. The proxy server knows where to send the request either because you issue a CONNECT command to it, or because you specify a full URL (instead of just the path portion) in the GET request. (The HTTP spec demonstrates the latter.) The response you'll get should be forwarded from the destination server, unless the proxy server has an error itself.
I think you can do it using Indy. You may find information in the Indy in Depth ebook.
Hope this helps.