6464# else
6565# undef SO_BPF_EXTENSIONS
6666# 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
6773#endif
6874
6975#include <stddef.h>
@@ -91,6 +97,18 @@ ZEND_DECLARE_MODULE_GLOBALS(sockets)
9197#define PF_INET AF_INET
9298#endif
9399
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+
94112static PHP_GINIT_FUNCTION (sockets );
95113static PHP_GSHUTDOWN_FUNCTION (sockets );
96114static PHP_MINIT_FUNCTION (sockets );
@@ -960,13 +978,16 @@ PHP_FUNCTION(socket_read)
960978/* {{{ 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. */
961979PHP_FUNCTION (socket_getsockname )
962980{
963- zval * arg1 , * addr , * port = NULL ;
981+ zval * arg1 , * addr , * objint = NULL ;
964982 php_sockaddr_storage sa_storage = {0 };
965983 php_socket * php_sock ;
966984 struct sockaddr * sa ;
967985 struct sockaddr_in * sin ;
968986#ifdef HAVE_IPV6
969987 struct sockaddr_in6 * sin6 ;
988+ #endif
989+ #ifdef AF_PACKET
990+ struct sockaddr_ll * sll ;
970991#endif
971992 char addrbuf [INET6_ADDRSTRLEN ];
972993 struct sockaddr_un * s_un ;
@@ -977,7 +998,7 @@ PHP_FUNCTION(socket_getsockname)
977998 Z_PARAM_OBJECT_OF_CLASS (arg1 , socket_ce )
978999 Z_PARAM_ZVAL (addr )
9791000 Z_PARAM_OPTIONAL
980- Z_PARAM_ZVAL (port )
1001+ Z_PARAM_ZVAL (objint )
9811002 ZEND_PARSE_PARAMETERS_END ();
9821003
9831004 php_sock = Z_SOCKET_P (arg1 );
@@ -997,8 +1018,8 @@ PHP_FUNCTION(socket_getsockname)
9971018 inet_ntop (AF_INET6 , & sin6 -> sin6_addr , addrbuf , sizeof (addrbuf ));
9981019 ZEND_TRY_ASSIGN_REF_STRING (addr , addrbuf );
9991020
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 ));
10021023 }
10031024 RETURN_TRUE ;
10041025 break ;
@@ -1008,8 +1029,8 @@ PHP_FUNCTION(socket_getsockname)
10081029 addr_string = inet_ntop (AF_INET , & sin -> sin_addr , addrbuf , sizeof (addrbuf ));
10091030 ZEND_TRY_ASSIGN_REF_STRING (addr , addr_string );
10101031
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 ));
10131034 }
10141035 RETURN_TRUE ;
10151036 break ;
@@ -1020,9 +1041,26 @@ PHP_FUNCTION(socket_getsockname)
10201041 ZEND_TRY_ASSIGN_REF_STRING (addr , s_un -> sun_path );
10211042 RETURN_TRUE ;
10221043 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
10231061
10241062 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" );
10261064 RETURN_THROWS ();
10271065 }
10281066}
@@ -1117,9 +1155,12 @@ PHP_FUNCTION(socket_create)
11171155 if (domain != AF_UNIX
11181156#ifdef HAVE_IPV6
11191157 && domain != AF_INET6
1158+ #endif
1159+ #ifdef AF_PACKET
1160+ & & domain != AF_PACKET
11201161#endif
11211162 && 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" );
11231164 RETURN_THROWS ();
11241165 }
11251166
@@ -1138,6 +1179,8 @@ PHP_FUNCTION(socket_create)
11381179 RETURN_THROWS ();
11391180 }
11401181
1182+ PHP_ETH_PROTO_CHECK (protocol , domain );
1183+
11411184 object_init_ex (return_value , socket_ce );
11421185 php_sock = Z_SOCKET_P (return_value );
11431186
@@ -1275,20 +1318,20 @@ PHP_FUNCTION(socket_bind)
12751318 php_socket * php_sock ;
12761319 char * addr ;
12771320 size_t addr_len ;
1278- zend_long port = 0 ;
1321+ zend_long objint = 0 ;
12791322 zend_long retval = 0 ;
12801323
12811324 ZEND_PARSE_PARAMETERS_START (2 , 3 )
12821325 Z_PARAM_OBJECT_OF_CLASS (arg1 , socket_ce )
12831326 Z_PARAM_STRING (addr , addr_len )
12841327 Z_PARAM_OPTIONAL
1285- Z_PARAM_LONG (port )
1328+ Z_PARAM_LONG (objint )
12861329 ZEND_PARSE_PARAMETERS_END ();
12871330
12881331 php_sock = Z_SOCKET_P (arg1 );
12891332 ENSURE_SOCKET_VALID (php_sock );
12901333
1291- if (port < 0 || port > USHRT_MAX ) {
1334+ if (objint < 0 || objint > USHRT_MAX ) {
12921335 zend_argument_value_error (3 , "must be between 0 and %u" , USHRT_MAX );
12931336 RETURN_THROWS ();
12941337 }
@@ -1316,7 +1359,7 @@ PHP_FUNCTION(socket_bind)
13161359 struct sockaddr_in * sa = (struct sockaddr_in * ) sock_type ;
13171360
13181361 sa -> sin_family = AF_INET ;
1319- sa -> sin_port = htons ((unsigned short ) port );
1362+ sa -> sin_port = htons ((unsigned short ) objint );
13201363
13211364 if (! php_set_inet_addr (sa , addr , php_sock )) {
13221365 RETURN_FALSE ;
@@ -1331,7 +1374,7 @@ PHP_FUNCTION(socket_bind)
13311374 struct sockaddr_in6 * sa = (struct sockaddr_in6 * ) sock_type ;
13321375
13331376 sa -> sin6_family = AF_INET6 ;
1334- sa -> sin6_port = htons ((unsigned short ) port );
1377+ sa -> sin6_port = htons ((unsigned short ) objint );
13351378
13361379 if (! php_set_inet6_addr (sa , addr , php_sock )) {
13371380 RETURN_FALSE ;
@@ -1340,9 +1383,26 @@ PHP_FUNCTION(socket_bind)
13401383 retval = bind (php_sock -> bsd_socket , (struct sockaddr * )sa , sizeof (struct sockaddr_in6 ));
13411384 break ;
13421385 }
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+ }
13431403#endif
13441404 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" );
13461406 RETURN_THROWS ();
13471407 }
13481408
@@ -1443,6 +1503,9 @@ PHP_FUNCTION(socket_recvfrom)
14431503 struct sockaddr_in sin ;
14441504#ifdef HAVE_IPV6
14451505 struct sockaddr_in6 sin6 ;
1506+ #endif
1507+ #ifdef AF_PACKET
1508+ //struct sockaddr_ll sll;
14461509#endif
14471510 char addrbuf [INET6_ADDRSTRLEN ];
14481511 socklen_t slen ;
@@ -1547,6 +1610,38 @@ PHP_FUNCTION(socket_recvfrom)
15471610 ZEND_TRY_ASSIGN_REF_STRING (arg5 , addrbuf [0 ] ? addrbuf : "::" );
15481611 ZEND_TRY_ASSIGN_REF_LONG (arg6 , ntohs (sin6 .sin6_port ));
15491612 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+ */
15501645#endif
15511646 default :
15521647 zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
@@ -1566,6 +1661,9 @@ PHP_FUNCTION(socket_sendto)
15661661 struct sockaddr_in sin ;
15671662#ifdef HAVE_IPV6
15681663 struct sockaddr_in6 sin6 ;
1664+ #endif
1665+ #ifdef AF_PACKET
1666+ //struct sockaddr_ll sll;
15691667#endif
15701668 int retval ;
15711669 size_t buf_len , addr_len ;
@@ -1639,6 +1737,22 @@ PHP_FUNCTION(socket_sendto)
16391737
16401738 retval = sendto (php_sock -> bsd_socket , buf , ((size_t )len > buf_len ) ? buf_len : (size_t )len , flags , (struct sockaddr * ) & sin6 , sizeof (sin6 ));
16411739 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+ */
16421756#endif
16431757 default :
16441758 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)
27022816
27032817 ai = Z_ADDRESS_INFO_P (arg1 );
27042818
2819+ PHP_ETH_PROTO_CHECK (ai -> addrinfo .ai_protocol , ai -> addrinfo .ai_family );
2820+
27052821 object_init_ex (return_value , socket_ce );
27062822 php_sock = Z_SOCKET_P (return_value );
27072823
@@ -2765,6 +2881,8 @@ PHP_FUNCTION(socket_addrinfo_connect)
27652881
27662882 ai = Z_ADDRESS_INFO_P (arg1 );
27672883
2884+ PHP_ETH_PROTO_CHECK (ai -> addrinfo .ai_protocol , ai -> addrinfo .ai_family );
2885+
27682886 object_init_ex (return_value , socket_ce );
27692887 php_sock = Z_SOCKET_P (return_value );
27702888
0 commit comments