Forum Moderators: coopster

Message Too Old, No Replies

Playing With Sockets With PHP

         

l008comm

9:02 am on Nov 14, 2013 (gmt 0)

10+ Year Member Top Contributors Of The Month



I'm trying to whip up some PHP that will open a TCP socket connection to a specified port on a specified host. That's all I'm doing is opening the connection, then closing it. I'm essentially just sniffing ports so I don't need to send or receive any data. I know of two ways to do this:
  1. fsockopen()
  2. socket_create(), socket_connect()


But as with all things in life, things get hung up in the details. There are two very important 'features' that I need.

First, I need to be able to bind this outgoing connection to alternate IP that my server has. This website is running on it's own unique IP, and this IP is not the server's default IP. So I'd like all outgoing connections from this site to also use this unique IP. As it turns out, you can bind to an IP using socket_bind() with the socket_create() function. It works nice and easy.

Second, I need to set a connection timeout. Not a read/write timeout, because I'm not actually reading or writing anything. I'm just opening the connection, and then closing it. So I need a way to apply a timeout to that process. As it turns out, fsockopen() supports connection timeouts by default, just stick an int as the 5th argument when calling the function. Nice and easy.

But the problem is that (as far as I've been able to learn), you can't bind to an IP with fsockopen() and you can't set a connection timeout with socket_create()/socket_connect(). Here is the code I have. I tried both techniques, but each one has it's corresponding flaw as mentioned above. using socket_create(), i've even tried setting the default_socket_timeout ini value using ini_set() but nothing seems to have any effect.

I've also read somewhere that I could possibly make socket_connect() connect using a non blocking connection. Which would not hold up the script while the connection is attempted. This why, I could simply give up waiting for a result after my $timeout. The problem is, other than casual mentions, I haven't been able to find any documentation or sample code of how you'd actually DO this. I don't know if it would even work.

So here is my original code, using fsockopen(). It has a connection timeout and it works great, except that the connections are coming from the wrong IP address because I haven't found any way to bind these connections to another IP address.

$sock = @fsockopen($ip,$port,$errno,$errstr,$timeout); if ($sock) { // Open fclose($sock); return 1; } else { if ($errno === 60) { // Timeout return 2; } else { // Closed return 3; } }

Here was my second try using socket_create() and socket_connect(). These connections are bound to the proper IP address, but there is no way to set a connection timeout. This means that if the port is blocked by a firewall, my PHP script will keep running for about 45 seconds until it gives up. In this code, I even tried setting the read and write timeouts to see if that would work, but it does not. Nor does setting the default_socket_timeout value.

ini_set("default_socket_timeout",$timeout); $sock = socket_create(AF_INET,SOCK_STREAM,SOL_TCP); socket_bind($sock,OPERATING_IP); socket_set_option($sock, SOL_SOCKET, SO_RCVTIMEO, array("sec" => $timeout, "usec" => 0)); socket_set_option($sock, SOL_SOCKET, SO_SNDTIMEO, array("sec" => $timeout, "usec" => 0)); $sock_status = @socket_connect($sock,$ip,$port); if ( $sock_status ) { // Open socket_close($sock); return 1; } else { $sock_error = socket_last_error($sock); if ($sock_error === 61) { // Closed return 3; } else { // Timeout return 2; } }

Anyway, this is my dilemma. I'm sure there must be some way to make this work, but it seems like PHP socket functions just aren't used that much, and because of that, they don't have nearly as much documentation and sample code across the internet.

[edited by: phranque at 11:35 pm (utc) on Dec 26, 2013]
[edit reason] syntax=php [/edit]

coopster

5:09 pm on Dec 26, 2013 (gmt 0)

WebmasterWorld Administrator 10+ Year Member



I looked at this for a bit today and couldn't come up with a quick answer either, l008comm. Have you considered cURL instead maybe?

brotherhood of LAN

7:32 pm on Dec 26, 2013 (gmt 0)

WebmasterWorld Senior Member 10+ Year Member Top Contributors Of The Month



cURL does allow you to choose the network interface and it's quite easy to use.

curl_setopt($handle,CURLOPT_INTERFACE,$interface_or_ip_to_use);

l008comm

11:15 pm on Dec 26, 2013 (gmt 0)

10+ Year Member Top Contributors Of The Month



Everyone suggests this on every forum I've posted this on. But I'm not downloading anything, I'm opening a connection on a tcp port, then closing it. Can you really ports can like that with curl? I don't think so?

phranque

11:38 pm on Dec 26, 2013 (gmt 0)

WebmasterWorld Administrator 10+ Year Member Top Contributors Of The Month



seems like socket_set_option should have done the job.
i would add proper error checking everywhere and try socket_set_option before socket_bind as in the example.

PHP: socket_set_option - Manual:
http://www.php.net/manual/en/function.socket-set-option.php [php.net]

also, i'm not a php expert, but "@socket_connect"?