64
64
# else
65
65
# undef SO_BPF_EXTENSIONS
66
66
# endif
67
+ # if defined(HAVE_LINUX_IF_PACKET_H )
68
+ # include <linux/if_packet.h>
69
+ # endif
70
+ # if defined(HAVE_LINUX_IF_ETHER_H )
71
+ # include <linux/if_ether.h>
72
+ # endif
67
73
#endif
68
74
69
75
#include <stddef.h>
@@ -91,6 +97,18 @@ ZEND_DECLARE_MODULE_GLOBALS(sockets)
91
97
#define PF_INET AF_INET
92
98
#endif
93
99
100
+ #if defined(AF_PACKET )
101
+ #define PHP_ETH_PROTO_CHECK (protocol , family ) \
102
+ do { \
103
+ /* We ll let EINVAL errno warning about miusage, too many protocols conflicts */ \
104
+ if (protocol <= USHRT_MAX && family == AF_PACKET) { \
105
+ protocol = htons(protocol); \
106
+ } \
107
+ } while (0)
108
+ #else
109
+ #define PHP_ETH_PROTO_CHECK (protocol , family ) (0)
110
+ #endif
111
+
94
112
static PHP_GINIT_FUNCTION (sockets );
95
113
static PHP_GSHUTDOWN_FUNCTION (sockets );
96
114
static PHP_MINIT_FUNCTION (sockets );
@@ -960,13 +978,16 @@ PHP_FUNCTION(socket_read)
960
978
/* {{{ Queries the remote side of the given socket which may either result in host/port or in a UNIX filesystem path, dependent on its type. */
961
979
PHP_FUNCTION (socket_getsockname )
962
980
{
963
- zval * arg1 , * addr , * port = NULL ;
981
+ zval * arg1 , * addr , * objint = NULL ;
964
982
php_sockaddr_storage sa_storage = {0 };
965
983
php_socket * php_sock ;
966
984
struct sockaddr * sa ;
967
985
struct sockaddr_in * sin ;
968
986
#ifdef HAVE_IPV6
969
987
struct sockaddr_in6 * sin6 ;
988
+ #endif
989
+ #ifdef AF_PACKET
990
+ struct sockaddr_ll * sll ;
970
991
#endif
971
992
char addrbuf [INET6_ADDRSTRLEN ];
972
993
struct sockaddr_un * s_un ;
@@ -977,7 +998,7 @@ PHP_FUNCTION(socket_getsockname)
977
998
Z_PARAM_OBJECT_OF_CLASS (arg1 , socket_ce )
978
999
Z_PARAM_ZVAL (addr )
979
1000
Z_PARAM_OPTIONAL
980
- Z_PARAM_ZVAL (port )
1001
+ Z_PARAM_ZVAL (objint )
981
1002
ZEND_PARSE_PARAMETERS_END ();
982
1003
983
1004
php_sock = Z_SOCKET_P (arg1 );
@@ -997,8 +1018,8 @@ PHP_FUNCTION(socket_getsockname)
997
1018
inet_ntop (AF_INET6 , & sin6 -> sin6_addr , addrbuf , sizeof (addrbuf ));
998
1019
ZEND_TRY_ASSIGN_REF_STRING (addr , addrbuf );
999
1020
1000
- if (port != NULL ) {
1001
- ZEND_TRY_ASSIGN_REF_LONG (port , htons (sin6 -> sin6_port ));
1021
+ if (objint != NULL ) {
1022
+ ZEND_TRY_ASSIGN_REF_LONG (objint , htons (sin6 -> sin6_port ));
1002
1023
}
1003
1024
RETURN_TRUE ;
1004
1025
break ;
@@ -1008,8 +1029,8 @@ PHP_FUNCTION(socket_getsockname)
1008
1029
addr_string = inet_ntop (AF_INET , & sin -> sin_addr , addrbuf , sizeof (addrbuf ));
1009
1030
ZEND_TRY_ASSIGN_REF_STRING (addr , addr_string );
1010
1031
1011
- if (port != NULL ) {
1012
- ZEND_TRY_ASSIGN_REF_LONG (port , htons (sin -> sin_port ));
1032
+ if (objint != NULL ) {
1033
+ ZEND_TRY_ASSIGN_REF_LONG (objint , htons (sin -> sin_port ));
1013
1034
}
1014
1035
RETURN_TRUE ;
1015
1036
break ;
@@ -1020,9 +1041,26 @@ PHP_FUNCTION(socket_getsockname)
1020
1041
ZEND_TRY_ASSIGN_REF_STRING (addr , s_un -> sun_path );
1021
1042
RETURN_TRUE ;
1022
1043
break ;
1044
+ #ifdef AF_PACKET
1045
+ case AF_PACKET :
1046
+ sll = (struct sockaddr_ll * ) sa ;
1047
+ char ifrname [IFNAMSIZ ];
1048
+
1049
+ if (UNEXPECTED (!if_indextoname (sll -> sll_ifindex , ifrname ))) {
1050
+ zend_throw_error (NULL , "invalid interface index" );
1051
+ RETURN_THROWS ();
1052
+ }
1053
+
1054
+ ZEND_TRY_ASSIGN_REF_STRING (addr , ifrname );
1055
+ if (objint != NULL ) {
1056
+ ZEND_TRY_ASSIGN_REF_LONG (objint , sll -> sll_ifindex );
1057
+ }
1058
+ RETURN_TRUE ;
1059
+ break ;
1060
+ #endif
1023
1061
1024
1062
default :
1025
- zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
1063
+ zend_argument_value_error (1 , "must be one of AF_UNIX, AF_PACKET, AF_INET, or AF_INET6" );
1026
1064
RETURN_THROWS ();
1027
1065
}
1028
1066
}
@@ -1117,9 +1155,12 @@ PHP_FUNCTION(socket_create)
1117
1155
if (domain != AF_UNIX
1118
1156
#ifdef HAVE_IPV6
1119
1157
&& domain != AF_INET6
1158
+ #endif
1159
+ #ifdef AF_PACKET
1160
+ & & domain != AF_PACKET
1120
1161
#endif
1121
1162
&& domain != AF_INET ) {
1122
- zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET6, or AF_INET" );
1163
+ zend_argument_value_error (1 , "must be one of AF_UNIX, AF_PACKET, AF_INET6, or AF_INET" );
1123
1164
RETURN_THROWS ();
1124
1165
}
1125
1166
@@ -1138,6 +1179,8 @@ PHP_FUNCTION(socket_create)
1138
1179
RETURN_THROWS ();
1139
1180
}
1140
1181
1182
+ PHP_ETH_PROTO_CHECK (protocol , domain );
1183
+
1141
1184
object_init_ex (return_value , socket_ce );
1142
1185
php_sock = Z_SOCKET_P (return_value );
1143
1186
@@ -1275,20 +1318,20 @@ PHP_FUNCTION(socket_bind)
1275
1318
php_socket * php_sock ;
1276
1319
char * addr ;
1277
1320
size_t addr_len ;
1278
- zend_long port = 0 ;
1321
+ zend_long objint = 0 ;
1279
1322
zend_long retval = 0 ;
1280
1323
1281
1324
ZEND_PARSE_PARAMETERS_START (2 , 3 )
1282
1325
Z_PARAM_OBJECT_OF_CLASS (arg1 , socket_ce )
1283
1326
Z_PARAM_STRING (addr , addr_len )
1284
1327
Z_PARAM_OPTIONAL
1285
- Z_PARAM_LONG (port )
1328
+ Z_PARAM_LONG (objint )
1286
1329
ZEND_PARSE_PARAMETERS_END ();
1287
1330
1288
1331
php_sock = Z_SOCKET_P (arg1 );
1289
1332
ENSURE_SOCKET_VALID (php_sock );
1290
1333
1291
- if (port < 0 || port > USHRT_MAX ) {
1334
+ if (objint < 0 || objint > USHRT_MAX ) {
1292
1335
zend_argument_value_error (3 , "must be between 0 and %u" , USHRT_MAX );
1293
1336
RETURN_THROWS ();
1294
1337
}
@@ -1316,7 +1359,7 @@ PHP_FUNCTION(socket_bind)
1316
1359
struct sockaddr_in * sa = (struct sockaddr_in * ) sock_type ;
1317
1360
1318
1361
sa -> sin_family = AF_INET ;
1319
- sa -> sin_port = htons ((unsigned short ) port );
1362
+ sa -> sin_port = htons ((unsigned short ) objint );
1320
1363
1321
1364
if (! php_set_inet_addr (sa , addr , php_sock )) {
1322
1365
RETURN_FALSE ;
@@ -1331,7 +1374,7 @@ PHP_FUNCTION(socket_bind)
1331
1374
struct sockaddr_in6 * sa = (struct sockaddr_in6 * ) sock_type ;
1332
1375
1333
1376
sa -> sin6_family = AF_INET6 ;
1334
- sa -> sin6_port = htons ((unsigned short ) port );
1377
+ sa -> sin6_port = htons ((unsigned short ) objint );
1335
1378
1336
1379
if (! php_set_inet6_addr (sa , addr , php_sock )) {
1337
1380
RETURN_FALSE ;
@@ -1340,9 +1383,26 @@ PHP_FUNCTION(socket_bind)
1340
1383
retval = bind (php_sock -> bsd_socket , (struct sockaddr * )sa , sizeof (struct sockaddr_in6 ));
1341
1384
break ;
1342
1385
}
1386
+ #endif
1387
+ #ifdef AF_PACKET
1388
+ case AF_PACKET :
1389
+ {
1390
+ struct sockaddr_ll * sa = (struct sockaddr_ll * ) sock_type ;
1391
+ socklen_t sa_len = sizeof (sa );
1392
+
1393
+ if (getsockname (php_sock -> bsd_socket , sock_type , & sa_len ) < 0 ) {
1394
+ zend_value_error ("invalid AF_PACKET socket" );
1395
+ RETURN_THROWS ();
1396
+ }
1397
+
1398
+ sa -> sll_ifindex = if_nametoindex (addr );
1399
+
1400
+ retval = bind (php_sock -> bsd_socket , sock_type , sizeof (struct sockaddr_ll ));
1401
+ break ;
1402
+ }
1343
1403
#endif
1344
1404
default :
1345
- zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
1405
+ zend_argument_value_error (1 , "must be one of AF_UNIX, AF_PACKET, AF_INET, or AF_INET6" );
1346
1406
RETURN_THROWS ();
1347
1407
}
1348
1408
@@ -1443,6 +1503,9 @@ PHP_FUNCTION(socket_recvfrom)
1443
1503
struct sockaddr_in sin ;
1444
1504
#ifdef HAVE_IPV6
1445
1505
struct sockaddr_in6 sin6 ;
1506
+ #endif
1507
+ #ifdef AF_PACKET
1508
+ //struct sockaddr_ll sll;
1446
1509
#endif
1447
1510
char addrbuf [INET6_ADDRSTRLEN ];
1448
1511
socklen_t slen ;
@@ -1547,6 +1610,38 @@ PHP_FUNCTION(socket_recvfrom)
1547
1610
ZEND_TRY_ASSIGN_REF_STRING (arg5 , addrbuf [0 ] ? addrbuf : "::" );
1548
1611
ZEND_TRY_ASSIGN_REF_LONG (arg6 , ntohs (sin6 .sin6_port ));
1549
1612
break ;
1613
+ #endif
1614
+ #ifdef AF_PACKET
1615
+ /*
1616
+ case AF_PACKET:
1617
+ // TODO expose and use proper ethernet frame type instead i.e. src mac, dst mac and payload to userland
1618
+ // ditto for socket_sendto
1619
+ slen = sizeof(sll);
1620
+ memset(&sll, 0, sizeof(sll));
1621
+ sll.sll_family = AF_PACKET;
1622
+ char ifrname[IFNAMSIZ];
1623
+
1624
+ retval = recvfrom(php_sock->bsd_socket, ZSTR_VAL(recv_buf), arg3, arg4, (struct sockaddr *)&sll, (socklen_t *)&slen);
1625
+
1626
+ if (retval < 0) {
1627
+ PHP_SOCKET_ERROR(php_sock, "unable to recvfrom", errno);
1628
+ zend_string_efree(recv_buf);
1629
+ RETURN_FALSE;
1630
+ }
1631
+ ZSTR_LEN(recv_buf) = retval;
1632
+ ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1633
+
1634
+ if (UNEXPECTED(!if_indextoname(sll.sll_ifindex, ifrname))) {
1635
+ PHP_SOCKET_ERROR(php_sock, "unable to get the interface name", errno);
1636
+ zend_string_efree(recv_buf);
1637
+ RETURN_FALSE;
1638
+ }
1639
+
1640
+ ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
1641
+ ZEND_TRY_ASSIGN_REF_STRING(arg5, ifrname);
1642
+ ZEND_TRY_ASSIGN_REF_LONG(arg6, sll.sll_ifindex);
1643
+ break;
1644
+ */
1550
1645
#endif
1551
1646
default :
1552
1647
zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
@@ -1566,6 +1661,9 @@ PHP_FUNCTION(socket_sendto)
1566
1661
struct sockaddr_in sin ;
1567
1662
#ifdef HAVE_IPV6
1568
1663
struct sockaddr_in6 sin6 ;
1664
+ #endif
1665
+ #ifdef AF_PACKET
1666
+ //struct sockaddr_ll sll;
1569
1667
#endif
1570
1668
int retval ;
1571
1669
size_t buf_len , addr_len ;
@@ -1639,6 +1737,22 @@ PHP_FUNCTION(socket_sendto)
1639
1737
1640
1738
retval = sendto (php_sock -> bsd_socket , buf , ((size_t )len > buf_len ) ? buf_len : (size_t )len , flags , (struct sockaddr * ) & sin6 , sizeof (sin6 ));
1641
1739
break ;
1740
+ #endif
1741
+ #ifdef AF_PACKET
1742
+ /*
1743
+ case AF_PACKET:
1744
+ if (port_is_null) {
1745
+ zend_argument_value_error(6, "cannot be null when the socket type is AF_PACKET");
1746
+ RETURN_THROWS();
1747
+ }
1748
+
1749
+ memset(&sll, 0, sizeof(sll));
1750
+ sll.sll_family = AF_PACKET;
1751
+ sll.sll_ifindex = port;
1752
+
1753
+ retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
1754
+ break;
1755
+ */
1642
1756
#endif
1643
1757
default :
1644
1758
zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
@@ -2702,6 +2816,8 @@ PHP_FUNCTION(socket_addrinfo_bind)
2702
2816
2703
2817
ai = Z_ADDRESS_INFO_P (arg1 );
2704
2818
2819
+ PHP_ETH_PROTO_CHECK (ai -> addrinfo .ai_protocol , ai -> addrinfo .ai_family );
2820
+
2705
2821
object_init_ex (return_value , socket_ce );
2706
2822
php_sock = Z_SOCKET_P (return_value );
2707
2823
@@ -2765,6 +2881,8 @@ PHP_FUNCTION(socket_addrinfo_connect)
2765
2881
2766
2882
ai = Z_ADDRESS_INFO_P (arg1 );
2767
2883
2884
+ PHP_ETH_PROTO_CHECK (ai -> addrinfo .ai_protocol , ai -> addrinfo .ai_family );
2885
+
2768
2886
object_init_ex (return_value , socket_ce );
2769
2887
php_sock = Z_SOCKET_P (return_value );
2770
2888
0 commit comments