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