Skip to content

Socket ether linux step2 #17926

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion ext/sockets/config.m4
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@ PHP_ARG_ENABLE([sockets],

if test "$PHP_SOCKETS" != "no"; then
AC_CHECK_FUNCS([hstrerror if_nametoindex if_indextoname sockatmark])
AC_CHECK_HEADERS([sys/sockio.h linux/filter.h linux/if_packet.h linux/if_ether.h linux/udp.h])
AC_CHECK_HEADERS([sys/sockio.h linux/filter.h linux/if_packet.h linux/if_ether.h netinet/ether.h])
AC_DEFINE([HAVE_SOCKETS], [1],
[Define to 1 if the PHP extension 'sockets' is available.])

9 changes: 9 additions & 0 deletions ext/sockets/php_sockets.h
Original file line number Diff line number Diff line change
@@ -77,6 +77,15 @@ typedef struct {

extern PHP_SOCKETS_API zend_class_entry *socket_ce;

#ifdef AF_PACKET
extern PHP_SOCKETS_API zend_class_entry *packet_ce;
extern PHP_SOCKETS_API zend_class_entry *ethinfopacket_ce;
extern PHP_SOCKETS_API zend_class_entry *tcppacket_ce;
extern PHP_SOCKETS_API zend_class_entry *udppacket_ce;
extern PHP_SOCKETS_API zend_class_entry *ipv4packet_ce;
extern PHP_SOCKETS_API zend_class_entry *ipv6packet_ce;
#endif

static inline php_socket *socket_from_obj(zend_object *obj) {
return (php_socket *)((char *)(obj) - XtOffsetOf(php_socket, std));
}
421 changes: 400 additions & 21 deletions ext/sockets/sockets.c

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions ext/sockets/sockets.stub.php
Original file line number Diff line number Diff line change
@@ -2,6 +2,7 @@

/** @generate-class-entries */

namespace {
/**
* @var int
* @cvalue AF_UNIX
@@ -2020,6 +2021,11 @@
* @cvalue ETH_P_ALL
*/
const ETH_P_ALL = UNKNOWN;
/**
* @var int
* @cvalue ETH_FRAME_LEN
*/
const ETH_FRAME_LEN = UNKNOWN;
#endif

#ifdef UDP_SEGMENT
@@ -2190,3 +2196,49 @@ function socket_wsaprotocol_info_import(string $info_id): Socket|false {}

function socket_wsaprotocol_info_release(string $info_id): bool {}
#endif
}

namespace Socket {
#ifdef AF_PACKET
class Packet
{
public int $headerSize;
public ?string $rawPacket;
}

final class EthernetPacket extends Packet
{
public \Socket $socket;
public int $ethProtocol;
public string $srcMac;
public string $dstMac;
public ?Packet $payload;
}

final class TcpPacket extends Packet
{
public int $srcPort;
public int $dstPort;
}

final class UdpPacket extends Packet
{
public int $srcPort;
public int $dstPort;
}

final class Ipv4Packet extends Packet
{
public string $srcAddr;
public string $dstAddr;
public ?Packet $payload;
}

final class Ipv6Packet extends Packet
{
public string $srcAddr;
public string $dstAddr;
public ?Packet $payload;
}
#endif
}
183 changes: 182 additions & 1 deletion ext/sockets/sockets_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

347 changes: 346 additions & 1 deletion ext/sockets/tests/socket_afpacket.phpt
Original file line number Diff line number Diff line change
@@ -15,7 +15,7 @@ if (!function_exists("posix_getuid") || posix_getuid() != 0) {
?>
--FILE--
<?php
$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IP);
$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$s_bind = socket_bind($s_c, 'lo');
var_dump($s_bind);

@@ -26,6 +26,205 @@ if (!function_exists("posix_getuid") || posix_getuid() != 0) {
var_dump($iindex);

socket_getpeername($s_c, $istr2, $iindex2);

$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_LOOP);
$v_bind = socket_bind($s_s, 'lo');

$buf = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_LOOP);
$buf .= str_repeat("A", 46);

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
var_dump(socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr));

var_dump($addr);
var_dump($rsp);

socket_close($s_c);
// purposely unsupported ethernet protocol (ARP)
$s_c = socket_create(AF_PACKET, SOCK_RAW, 0x0806);
$s_bind = socket_bind($s_c, 'lo');
$buf = pack("H12H12n", "ffffffffffff", "000000000000", 0x0806);
$buf .= str_repeat("A", 46);

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));

try {
socket_recvfrom($s_c, $rsp2, strlen($buf), 0, $addr2);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}

socket_close($s_c);
socket_close($s_s);

$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$s_bind = socket_bind($s_c, 'lo');

$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IP);
$v_bind = socket_bind($s_s, 'lo');

$ip = hex2bin(
"4500" .
"0028" .
"0000" .
"4000" .
"4006" .
"0000" .
"7f000001" .
"7f000001"
);
$p = str_repeat("A", 20);

$buf = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_IP);
$buf .= $ip . $p;

$min_frame_size = 60;
$buf .= str_repeat("\x00", max(0, $min_frame_size - strlen($buf)));

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
var_dump(socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr));

var_dump($addr);
var_dump($rsp);

socket_close($s_s);
socket_close($s_c);

$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
$s_bind = socket_bind($s_c, 'lo');
$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
$v_bind = socket_bind($s_s, 'lo');

$ethhdr = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_IPV6);

$ipv6_first_4 = hex2bin("60000000");

$ipv6_payload_len = hex2bin("0014");

$ipv6_nexthdr = chr(6);

$ipv6_hop_limit = chr(64);

$src_ip = hex2bin("00000000000000000000000000000001");

$dst_ip = hex2bin("00000000000000000000000000000001");

$tcp_hdr = pack("nnNNCCnn",
12345,
80,
0,
0,
(5 << 4),
0x02,
65535,
0
);

$buf = $ethhdr
. $ipv6_first_4
. $ipv6_payload_len
. $ipv6_nexthdr
. $ipv6_hop_limit
. $src_ip
. $dst_ip
. $tcp_hdr;

$buf .= str_repeat("\x00", max(0, 60 - strlen($buf)));

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
var_dump(socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr));

var_dump($addr);
var_dump($rsp);

$first_4_bytes = hex2bin("60000000");

$payload_len = hex2bin("0014");

$nexthdr = hex2bin("43"); // Extended proto

$hop_limit = hex2bin("40");

$src_ip = hex2bin("00000000000000000000000000000001");

$dst_ip = hex2bin("00000000000000000000000000000001");

$tcp_payload = str_repeat("A", 20);

$ethhdr = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_IPV6);

$buf = $ethhdr . $first_4_bytes . $payload_len . $nexthdr . $hop_limit . $src_ip . $dst_ip . $tcp_payload;

$buf .= str_repeat("\x00", max(0, 60 - strlen($buf)));

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));

try {
socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}

socket_close($s_s);
socket_close($s_c);

$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IP);
$s_bind = socket_bind($s_c, 'lo');

$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_IP);
$v_bind = socket_bind($s_s, 'lo');

$ip = hex2bin(
"4500" .
str_repeat("0028", 16) .
"0000" .
"4000" .
"4006" .
"0000" .
"7f000001" .
"7f000001"
);
$p = str_repeat("A", 20);

$buf = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_IP);
$buf .= $ip . $p;

$min_frame_size = 60;
$buf .= str_repeat("\x00", max(0, $min_frame_size - strlen($buf)));

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));

try {
socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}

$ip = hex2bin(
"9999" .
"0028" .
"0000" .
"4000" .
"4006" .
"0000" .
"FFFFFeFF" .
"7f000001"
);
$p = str_repeat("Bb", 80);

$buf = pack("H12H12n", "ffffffffffffh", "aaaaaAAAAAAA", ETH_P_IP);
$buf .= $ip . $p;

$min_frame_size = 60;
$buf .= str_repeat("\x00", max(0, $min_frame_size - strlen($buf)));

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
var_dump(socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr));

var_dump($addr);
var_dump($rsp);

socket_close($s_s);
socket_close($s_c);
?>
--EXPECTF--
@@ -35,3 +234,149 @@ string(2) "lo"
int(%i)

Warning: socket_getpeername(): unable to retrieve peer name [95]: %sot supported in %s on line %d
int(60)
int(60)
string(2) "lo"
object(Socket\EthernetPacket)#3 (%d) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["socket"]=>
object(Socket)#1 (0) {
}
["ethProtocol"]=>
int(%i)
["srcMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["dstMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["payload"]=>
%a
}
int(60)
unsupported ethernet protocol
int(60)
int(%d)
string(2) "lo"
object(Socket\EthernetPacket)#2 (7) {
["headerSize"]=>
int(14)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["socket"]=>
object(Socket)#%d (0) {
}
["ethProtocol"]=>
int(2048)
["srcMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["dstMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["payload"]=>
object(Socket\Ipv4Packet)#%d (5) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["srcAddr"]=>
string(%d) "%d.%d.%d.%d"
["dstAddr"]=>
string(%d) "%d.%d.%d.%d"
["payload"]=>
object(Socket\%sPacket)#%d (4) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["srcPort"]=>
int(%d)
["dstPort"]=>
int(%d)
}
}
}
int(%d)
int(%d)
string(2) "lo"
object(Socket\EthernetPacket)#%d (7) {
["headerSize"]=>
int(14)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["socket"]=>
object(Socket)#3 (0) {
}
["ethProtocol"]=>
int(%d)
["srcMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["dstMac"]=>
string(%d) "%s:%s:%s:%s:%s:%s"
["payload"]=>
object(Socket\Ipv6Packet)#%d (5) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%A"
["srcAddr"]=>
string(%d) "%s"
["dstAddr"]=>
string(%d) "%s"
["payload"]=>
object(Socket\TcpPacket)#%d (4) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["srcPort"]=>
int(%d)
["dstPort"]=>
int(%d)
}
}
}
int(%d)
unsupported ipv6 header protocol
int(%d)
unsupported ip header protocol
int(%d)
int(%d)
string(%d) "%s"
object(Socket\EthernetPacket)#%d (7) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["socket"]=>
object(Socket)#%d (0) {
}
["ethProtocol"]=>
int(2048)
["srcMac"]=>
string(17) "aa:aa:aa:aa:aa:aa"
["dstMac"]=>
string(17) "ff:ff:ff:ff:ff:ff"
["payload"]=>
object(Socket\Ipv4Packet)#%d (5) {
["headerSize"]=>
int(40)
["rawPacket"]=>
string(%d) "%s"
["srcAddr"]=>
string(15) "%s.%s.%s.%s"
["dstAddr"]=>
string(9) "%s.%s.%s.%s"
["payload"]=>
object(Socket\TcpPacket)#%d (4) {
["headerSize"]=>
int(%d)
["rawPacket"]=>
string(%d) "%r(.|\n)*?"%r
["srcPort"]=>
int(%d)
["dstPort"]=>
int(%d)
}
}
}
65 changes: 65 additions & 0 deletions ext/sockets/tests/socket_afpacket_error.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
--TEST--
AF_PACKET sockets handling errors
--EXTENSIONS--
sockets
posix
--SKIPIF--
<?php

if (!defined("AF_PACKET")) {
die('SKIP AF_PACKET not supported on this platform.');
}
if (!function_exists("posix_getuid") || posix_getuid() != 0) {
die('SKIP AF_PACKET requires root permissions.');
}
?>
--FILE--
<?php
$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$s_bind = socket_bind($s_c, 'lo');

$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$v_bind = socket_bind($s_s, 'lo');

$payload = random_bytes(1024);
$payload .= str_repeat("A", 46);

$buf = pack("H12H12n", "ffffffffffff", "000000000000", 0x0806);
$buf .= $payload;

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));

try {
socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}

socket_close($s_s);
socket_close($s_c);

$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$s_bind = socket_bind($s_c, 'lo');

$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
$v_bind = socket_bind($s_s, 'lo');

$buf = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_IP);
$buf .= str_repeat("A", 46);

var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));

try {
socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr);
} catch (\ValueError $e) {
echo $e->getMessage(), PHP_EOL;
}

socket_close($s_s);
socket_close($s_c);
?>
--EXPECTF--
int(1084)
unsupported %s protocol
int(60)
invalid transport header length