I would like to expose a service written in Perl to localhost HTTP requests. I do not want to modify Apache configuration. How to check whether a Perl CGI HTTP request originates from localhost?
I want for this check to succeed even if this call is made through a virtual host eg. https://www.myserivce.com/hidden/service.pl given that the call is made from inside of www.myserivce.com.
REMOTE_ADDR, but that's a dumb way to do it because you put the authentication logic in the application.
Instead, bind a stand-alone Web server to local interface only, thus the operating system's IP/networking stack guarantees that no request from outside can reach the server.
I think that if you put in /etc/hosts file an entry with myservice.com and ip 127.0.0.1 then all the requests from localhost to your site will have the REMOTE_ADDR set to 127.0.0.1 .
I am afraid that this is the only way to do it, unless you are making requests to 127.0.0.1/hidden/service.pl instead of myservice.com/hidden/service.pl
I have used the following code:
my $server_addr = inet_ntoa(scalar gethostbyname(hostname() || 'localhost'));
my $call_addr = $query->remote_addr();
die unless $call_addr eq "127.0.0.1" || $call_addr eq $server_addr;
I do not think it covers all cases, but seems to work with my setup. If anybody knows a generic solution then please submit it here.
Related
I have been trying to set the subdomain in localtunnel, but it keeps throwing me different subdomains.
Port number is 4000 and it's running.
The command which I used :
lt --port 4000 --subdomain xyz (I changed subdomain name for the security reason).
Where am I doing wrong?
I know it is a very late answer, but for the help of others searchers who get to this link, and are not able to find a valid answer, for those users I am writing this answer
The command which I used : lt --port 4000 --subdomain xyz (I changed
subdomain name for the security reason).
The first thing is that the command is ok but before local tunnel assigns you a subdomain it must be available first.
Now you may be thinking that I am using a private very unique domain name which should have available, yes you are right but remember local tunnel keeps the record of subdomains provided by you and builds his private database which contains enough pool for random subdomain assigning feature.
Which now clears that after one, two or even more (non-consecutive) attempts it is possible that your domain assigned to someone else so that for that period you can obviously not use that domain, however whenever that domain will be freed, you will be assigned the requested domain for sure.
I'm not familiar enough with localtunnel to tell you what's wrong there, but I can tell you how to accomplish your same goal using Telebit:
(p.s. Did you figure this out? If so, I'd love to hear how you did it and I'm sure others would too)
Install
curl https://get.telebit.io | bash
You can also install via npm... but that isn't the preferred install method at this time. There may be some caveats.
The random domain you get is attached to your account (hence the need for email) and it's encrypted end-to-end with Greenlock via Let's Encrypt.
Configure
./telebit http 4000 xyz
The general format is
./telebit <protocol> <port> [subdomain]
It's not just https, you can use it to tunnel anything over tls/ssl (plain tcp, ssh, openvpn, etc).
Custom domains are not yet a generally available feature, but they're on the horizon.
Breif Description of what I am trying to accomplish. So I am working with Crestrons Simpl+ software. My job is to create a module for a sound masking system called QT Pro. Now, QT Pro has an API where you can control it via HTTP. I need a way to establish a connection with the QT Pro via HTTP( I have everything I need, IP, Username, Password).
Whats the problem? I have just started working with this language. Unfortunately there isn't as much documentation as I would like, otherwise I wouldn't be here. I know I need to create a socket connection via TCP on port 80. I just don't know what I'm supposed to send through it.
Here is an example:
http://username:password#address/cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value
&mN=Value&auxA=Value&auxB=Value&autoR=Value
If I were to put this into the URL box, and fill it in correctly. then it would change the values that I specify. Am I supposed to send the entire thing? Or just after cmd.htm? Or is there some other way I'm supposed to send data? I'd like to stay away from the TCP/IP Module so I can keep this all within the same module.
Thanks.
You send
GET /cmd.htm?cmd=setOneZoneData&ZN=Value&mD=Value&mN=Value&auxA=Value&auxB=Value&autoR=Value HTTP/1.1
Host: address
Connection: close
(End with a couple of newlines.)
If you need to use HTTP basic authentication, then also include a header like
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
where the gibberish is the base64-encoded version of username:password.
But surely there is some mechanism for opening HTTP connections already there for you? Just blindly throwing out headers like this and hoping the response is what you expect is not robust, to say the least.
To see what is going on with your requests and responses, a great tool is netcat (or telnet, for that matter.)
Do nc address 80 to connect to server address on port 80, then paste your HTTP request:
GET /cmd.htm HTTP/1.1
Host: address
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
Connection: close
and see what comes back. SOMETHING should come back. (Remember to terminate with two newlines.)
To see what requests your browser is sending when you do something that works, you can listen like this: nc -l -p 8080.
Then direct your browser to localhost:8080 with the rest of the URL as before, and you'll see the request that was sent. (Then you can type back to see how the browser handles the response.)
The Plack suite commonly uses the http://0:port. E.g. the following
plackup -MPlack::App::Directory -e 'Plack::App::Directory->new(root=>".");'
prints
HTTP::Server::PSGI: Accepting connections at http://0:5000/
However, the LWP::UserAgent (or some deeper called modules) didn't accepts it, e.g. the:
perl -MLWP::UserAgent -E '$u=LWP::UserAgent->new;$res=$u->get("http://0:5000/valid/path");print $res->status_line'
prints:
500 No Host option provided
but the
perl -MLWP::UserAgent -E '$u=LWP::UserAgent->new;$res=$u->get("http://localhost:5000/valid/path");print $res->status_line'
prints
200 OK
The question is: who is wrong?
Is the http://0:port valid, e.g. the LWP is "wrong"
or it isn't valid and the PSGI uses it as only "randomly valid" shortcut?
The output of the Plack suite is the output of a server. A server typically binds a socket to a certain port and address in order to serve content there.
The notation http://0:port means in this case: listen on port port on all addresses of this machine. This is handy if you don't know or don't want to specify all addresses of the machine where the server should be reachable.
The output of the LWP::UserAgent ist the output of a client. In order to open a connection to a server, you must explicitly specify the address and the port to connect to. 0 is no valid IP address, therefore the connection fails when you connect to http://0:port.
Safari 11, curl and wget resolve http://0:5000 to http://0.0.0.0:5000 and connect to the localhost.
I just tested it, after seeing the URL and finding the answer to the question dissatisfying.
I am getting the following from a script I am trying to run:
Notice: fwrite() [function.fwrite]: send of 7 bytes failed with errno=1 Operation not permitted in /home/thrawn/public_html/sorcero.us/MinecraftQuery.class.php on line 165
However, when I check phpinfo(), allow_url_fopen is on and Sockets Support is Enabled. I haven't been able to find anything pointing me to what might be causing this.
For clarification, I did not write this script. My knowledge of PHP is mostly just the basics, but I know enough to reason that this should be working since phpinfo() says the correct things are permitted. The script in question is here: https://github.com/xPaw/PHP-Minecraft-Query/blob/master/MinecraftQuery.class.php
fwrite() writes to $this->socket and is in private function WriteData(). In public function Connect() is a line
$this->Socket = #FSockOpen( 'udp://' . $Ip, (int)$Port, $ErrNo, $ErrStr, $Timeout );
This is the only line in this file where $this->socket is written.
Also, there is a warning message in the manpage for fsockopen()
UDP sockets will sometimes appear to have opened without an error,
even if the remote host is unreachable. The error will only become
apparent when you read or write data to/from the socket. The reason
for this is because UDP is a "connectionless" protocol, which means
that the operating system does not try to establish a link for the
socket until it actually needs to send or receive data.
This is probably the case. The socket is created although the ip adddress or the port is not reachable. This results in an error message when trying to write data.
So in order to resolve this, you would need to do at least these things:
Make sure the ip address and port are correct.
Verify that the server is up and running.
Make sure the ip address and port are reachable (not blocked in any firewalls)
I do not know what the correct settings should be. If you have installed the software on an external server, also try your local computer so you have a way to verify the ip address and port settings.
If you checked your PHP configuration and the problem persists, check your firewall log.
As Ignacio Vazquez-Abrams stated: this is an OS error.
In my case, CSF was blocking outgoing connections.
Seems like permission error,
Try,
chmod -R folder_to_be_file_written
Then execute php script
For example http://www.utorrent.com/testport?port=12345
How does this work? Can the server side script attempt to open a socket?
There are many ways of accomplishing this through server-side scripting. As #Oded mentioned, most server-side handlers are capable of initiating socket connections on arbitrary ports, and most of those even have dedicated port-scanning packages/libraries (PHP has one in the PEAR repository, Python's 'socket' module makes this type of tasks a breeze, etc...)
Keep in mind that on shared host platforms, socket connections are typically disabled for security purposes.
Another way that is also very easy to accomplish is to use a command-line port-scanner such as nmap from your server-side script. i.e in PHP, you would do echo ``nmap -p $port $ip\
The server side script will try to open a connection on the specified port to the originating IP.
If there is no response (the attempt will timeout), this would be an indication that the port is not open.
The server can try, as #Oded said. But that doesn't ensure the receiver will respond.
Typically, something like this happens:
The URL request contains instructions about which port to access. The headers that your browser sends include information about where the request is originating from.
Before responding to the request, the server tries to open a port and checks if this is successful. It waits a while before timing out.
The webpage is rendered dynamically based on the results of this test.
The response is returned to you containing the results.
Sometimes steps (2) and (3) will be replaced with an AJAX callback, which allows the response to return sooner.