Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I pass a TCP socket resource via socket_sendmsg (sendmsg) to a AF_UNIX local socket and if so how

My goal is to pass along a socket connection (once 'handshaken' (http upgraded) and 'authenticated' (my own function that does a challenge using the provided details against my db))to another php script process (not forked) so that it can add it to its own array of socket resource "authenticated clients" and take over the connection. Once it's sent via the php wrapper of sendmsg (socket_sendmsg - who's PHP documentation is inaccurate and so I've mostly been looking at people trying to do the same in c)

If I send:

socket_sendmsg($hsSocket, ["iov" => [json_encode(array('action'=>'add','uID'=>$messageObj->uID,'uDatID'=>$messageObj->uDatID,'sessID'=>$messageObj->sessID))], "control" => [["level" => SOL_SOCKET, "type" => SCM_RIGHTS, "data" => [$authlogfd]]]], 0);

which is sending the File Descriptor of an open log file, if I then do (after socket_select on that resourceArray):

    if(socket_recvmsg($arrayOfSocketResources, $hsSocketData,MSG_DONTWAIT)){
                printf("SS:HS: got recvmsg control data\n");
                print_r($hsSocketData);
                if(isset($hsSocketData['control'][0]['data'][0])){
                $newlogfd=$hsSocketData['control'][0]['data'][0];   
                $msg=json_decode($hsSocketData['iov'][0],true);
                if(isset($msg['action'])&&$msg['action']=='add'){
                $sendmsg=PHP_EOL."from second script".PHP_EOL;
                fwrite($newlogfd,$sendmsg,strlen($sendmsg));
                printf("SS:HS: got descriptor %s action:%s uID:%s uDatID:%s sessID:%s\n",$newlogfd,$msg['action'],$msg['uID'],$msg['uDatID'],$msg['sessID']);
                }

Then I see the message "from second script" in the log (so I'm able to write to the file descriptor passed - even after the passer is closed (there's a count for every process attached to the File Description or something that gets incremented)). This also works to STDOUT if I send that from the passer instead of the log File Descriptor.

When I change to sending one of the authenticated tcp socket client resources, it shows a resource id if I dump:

          Array(
[name] => 
[control] => Array
    ([0] => Array
            (
                [level] => 1
                [type] => 1
                [data] => Array
                    (
                        [0] => Resource id #12
                    )

            )

    )

[iov] => Array
    (
        [0] => {"action":"add","uID":"816-2554846393-11","uDatID":"fe1eba892f2144b3c9ce49f79c7a8386","sessID":"9mpr38o5nrmqke0mfejvn3801l"}
    )

[flags] => 0

)

The problem is when I try to use the passed socket resource "Resource id #12" I get

socket_send(): supplied resource is not a valid Socket

A socket_select with "Resource id #12" added to its read resource array also borks complaining that it's invalid.

Is what I'm trying to do with passing the socket in some way different here? What am I missing (besides the obvious things).

like image 424
Ryan Barrett Avatar asked Dec 21 '25 00:12

Ryan Barrett


1 Answers

$r = socket_sendmsg($authSocket, ["iov" => [json_encode(array('uID'=>$socketMYSQL->unboxID($messageObj->uID),'uDatID'=>$messageObj->uDatID,'sessID'=>$messageObj->sessID))], "control" => [["level" => SOL_SOCKET, "type" => SCM_RIGHTS, "data" => [socket_export_stream($newSocketArrayResource),STDOUT]]]], 0);

socket_export_stream() is the magic I was missing (I think it encapsulates the socket in the stream object) now when I var_dump on the received fd I get

resource(13) of type (Socket)

instead of

resource(13) of type (stream)

and socket_getpeername() works

like image 77
Ryan Barrett Avatar answered Dec 23 '25 13:12

Ryan Barrett



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!