41
41
# include <netdb.h>
42
42
# include <netinet/in.h>
43
43
# include <netinet/tcp.h>
44
+ # include <netinet/udp.h>
44
45
# include <sys/un.h>
45
46
# include <arpa/inet.h>
46
47
# include <sys/time.h>
54
55
# ifdef HAVE_IF_NAMETOINDEX
55
56
# include <net/if.h>
56
57
# endif
58
+ # ifdef HAVE_NETINET_ETHER_H
59
+ # include <netinet/ether.h>
60
+ # include <netinet/ip.h>
61
+ # include <linux/ipv6.h>
62
+ # endif
57
63
# if defined(HAVE_LINUX_SOCK_DIAG_H )
58
64
# include <linux/sock_diag.h>
59
65
# else
@@ -120,6 +126,9 @@ static PHP_RSHUTDOWN_FUNCTION(sockets);
120
126
121
127
zend_class_entry * socket_ce ;
122
128
static zend_object_handlers socket_object_handlers ;
129
+ #ifdef AF_PACKET
130
+ zend_class_entry * socket_ethinfo_ce ;
131
+ #endif
123
132
124
133
static zend_object * socket_create_object (zend_class_entry * class_type ) {
125
134
php_socket * intern = zend_object_alloc (sizeof (php_socket ), class_type );
@@ -482,6 +491,9 @@ static PHP_MINIT_FUNCTION(sockets)
482
491
socket_object_handlers .get_gc = socket_get_gc ;
483
492
socket_object_handlers .compare = zend_objects_not_comparable ;
484
493
494
+ #if defined(AF_PACKET )
495
+ socket_ethinfo_ce = register_class_SocketEthernetInfo ();
496
+ #endif
485
497
address_info_ce = register_class_AddressInfo ();
486
498
address_info_ce -> create_object = address_info_create_object ;
487
499
address_info_ce -> default_object_handlers = & address_info_object_handlers ;
@@ -1388,7 +1400,7 @@ PHP_FUNCTION(socket_bind)
1388
1400
struct sockaddr_ll * sa = (struct sockaddr_ll * ) sock_type ;
1389
1401
socklen_t sa_len = sizeof (sa );
1390
1402
1391
- if (getsockname (php_sock -> bsd_socket , sock_type , & sa_len ) < 0 ) {
1403
+ if (getsockname (php_sock -> bsd_socket , ( struct sockaddr * ) sa , & sa_len ) < 0 ) {
1392
1404
zend_value_error ("invalid AF_PACKET socket" );
1393
1405
RETURN_THROWS ();
1394
1406
}
@@ -1503,7 +1515,9 @@ PHP_FUNCTION(socket_recvfrom)
1503
1515
struct sockaddr_in6 sin6 ;
1504
1516
#endif
1505
1517
#ifdef AF_PACKET
1506
- //struct sockaddr_ll sll;
1518
+ struct sockaddr_ll sll ;
1519
+ int protoid ;
1520
+ socklen_t protoidlen = sizeof (protoid );
1507
1521
#endif
1508
1522
char addrbuf [INET6_ADDRSTRLEN ];
1509
1523
socklen_t slen ;
@@ -1532,6 +1546,15 @@ PHP_FUNCTION(socket_recvfrom)
1532
1546
RETURN_FALSE ;
1533
1547
}
1534
1548
1549
+ #ifdef AF_PACKET
1550
+ // ethernet header + payload
1551
+ // possibly follow-up PR SOCK_DGRAM
1552
+ if (php_sock -> type == AF_PACKET && arg3 < 60 ) {
1553
+ zend_argument_value_error (3 , "must be at least 60 for AF_PACKET" );
1554
+ RETURN_THROWS ();
1555
+ }
1556
+ #endif
1557
+
1535
1558
recv_buf = zend_string_alloc (arg3 + 1 , 0 );
1536
1559
1537
1560
switch (php_sock -> type ) {
@@ -1610,14 +1633,19 @@ PHP_FUNCTION(socket_recvfrom)
1610
1633
break ;
1611
1634
#endif
1612
1635
#ifdef AF_PACKET
1613
- /*
1614
1636
case AF_PACKET :
1615
- // TODO expose and use proper ethernet frame type instead i.e. src mac, dst mac and payload to userland
1616
- // ditto for socket_sendto
1637
+ getsockopt (php_sock -> bsd_socket , SOL_SOCKET , SO_TYPE , (char * ) & protoid , & protoidlen );
1638
+
1639
+ // TODO: SOCK_DGRAM support
1640
+ if (protoid != SOCK_RAW ) {
1641
+ zend_argument_value_error (1 , "must be SOCK_RAW socket type" );
1642
+ RETURN_THROWS ();
1643
+ }
1617
1644
slen = sizeof (sll );
1618
1645
memset (& sll , 0 , sizeof (sll ));
1619
1646
sll .sll_family = AF_PACKET ;
1620
1647
char ifrname [IFNAMSIZ ];
1648
+ zval zpayload ;
1621
1649
1622
1650
retval = recvfrom (php_sock -> bsd_socket , ZSTR_VAL (recv_buf ), arg3 , arg4 , (struct sockaddr * )& sll , (socklen_t * )& slen );
1623
1651
@@ -1626,20 +1654,93 @@ PHP_FUNCTION(socket_recvfrom)
1626
1654
zend_string_efree (recv_buf );
1627
1655
RETURN_FALSE ;
1628
1656
}
1629
- ZSTR_LEN(recv_buf) = retval;
1630
- ZSTR_VAL(recv_buf)[ZSTR_LEN(recv_buf)] = '\0';
1631
1657
1632
1658
if (UNEXPECTED (!if_indextoname (sll .sll_ifindex , ifrname ))) {
1633
1659
PHP_SOCKET_ERROR (php_sock , "unable to get the interface name" , errno );
1634
1660
zend_string_efree (recv_buf );
1635
1661
RETURN_FALSE ;
1636
1662
}
1637
1663
1638
- ZEND_TRY_ASSIGN_REF_NEW_STR(arg2, recv_buf);
1664
+ struct ethhdr * e = (struct ethhdr * )ZSTR_VAL (recv_buf );
1665
+ unsigned short protocol = ntohs (e -> h_proto );
1666
+ unsigned char * payload ;
1667
+
1668
+ zval obj ;
1669
+ object_init_ex (& obj , socket_ethinfo_ce );
1670
+ array_init (& zpayload );
1671
+
1672
+ switch (protocol ) {
1673
+ case ETH_P_IP : {
1674
+ payload = ((unsigned char * )e + sizeof (struct ethhdr ));
1675
+ struct iphdr * ip = (struct iphdr * )payload ;
1676
+ unsigned char * ipdata = payload + (ip -> ihl * 4 );
1677
+ struct in_addr s , d ;
1678
+ s .s_addr = ip -> saddr ;
1679
+ d .s_addr = ip -> daddr ;
1680
+ add_assoc_string (& zpayload , "ipsrc" , inet_ntoa (s ));
1681
+ add_assoc_string (& zpayload , "ipdst" , inet_ntoa (d ));
1682
+
1683
+ switch (ip -> protocol ) {
1684
+ case IPPROTO_TCP : {
1685
+ struct tcphdr * tcp = (struct tcphdr * )ipdata ;
1686
+ add_assoc_long (& zpayload , "portsrc" , ntohs (tcp -> th_sport ));
1687
+ add_assoc_long (& zpayload , "portdst" , ntohs (tcp -> th_dport ));
1688
+ break ;
1689
+ }
1690
+ case IPPROTO_UDP : {
1691
+ struct udphdr * udp = (struct udphdr * )ipdata ;
1692
+ add_assoc_long (& zpayload , "portsrc" , ntohs (udp -> uh_sport ));
1693
+ add_assoc_long (& zpayload , "portdst" , ntohs (udp -> uh_dport ));
1694
+ break ;
1695
+ }
1696
+ default :
1697
+ zend_string_efree (recv_buf );
1698
+ zval_ptr_dtor (& zpayload );
1699
+ zval_ptr_dtor (& obj );
1700
+ zend_value_error ("unsupported ip header protocol" );
1701
+ RETURN_THROWS ();
1702
+ }
1703
+ break ;
1704
+ }
1705
+ case ETH_P_IPV6 : {
1706
+ payload = ((unsigned char * )e + sizeof (struct ethhdr ));
1707
+ struct ipv6hdr * ip = (struct ipv6hdr * )payload ;
1708
+ char s [INET6_ADDRSTRLEN ], d [INET6_ADDRSTRLEN ];
1709
+ inet_ntop (AF_INET6 , & ip -> saddr , s , sizeof (s ));
1710
+ inet_ntop (AF_INET6 , & ip -> daddr , d , sizeof (d ));
1711
+ add_assoc_string (& zpayload , "ipsrc" , s );
1712
+ add_assoc_string (& zpayload , "ipdst" , d );
1713
+ break ;
1714
+ }
1715
+ case ETH_P_LOOP : {
1716
+ struct ethhdr * innere = (struct ethhdr * )((unsigned char * )e + ETH_HLEN );
1717
+ add_assoc_string (& zpayload , "macsrc" , ether_ntoa ((struct ether_addr * )innere -> h_source ));
1718
+ add_assoc_string (& zpayload , "macdst" , ether_ntoa ((struct ether_addr * )innere -> h_dest ));
1719
+ break ;
1720
+ }
1721
+ default :
1722
+ zend_string_efree (recv_buf );
1723
+ zval_ptr_dtor (& zpayload );
1724
+ zval_ptr_dtor (& obj );
1725
+ zend_value_error ("unsupported ethernet protocol" );
1726
+ RETURN_THROWS ();
1727
+ }
1728
+
1729
+ Z_DELREF (zpayload );
1730
+ zend_string_efree (recv_buf );
1731
+ zend_update_property (Z_OBJCE (obj ), Z_OBJ (obj ), ZEND_STRL ("socket" ), arg1 );
1732
+ zend_update_property_string (Z_OBJCE (obj ), Z_OBJ (obj ), ZEND_STRL ("macsrc" ), ether_ntoa ((struct ether_addr * )e -> h_source ));
1733
+ zend_update_property_string (Z_OBJCE (obj ), Z_OBJ (obj ), ZEND_STRL ("macdst" ), ether_ntoa ((struct ether_addr * )e -> h_dest ));
1734
+ zend_update_property_long (Z_OBJCE (obj ), Z_OBJ (obj ), ZEND_STRL ("ethprotocol" ), protocol );
1735
+ zend_update_property (Z_OBJCE (obj ), Z_OBJ (obj ), ZEND_STRL ("payload" ), & zpayload );
1736
+
1737
+ ZEND_TRY_ASSIGN_REF_VALUE (arg2 , & obj );
1639
1738
ZEND_TRY_ASSIGN_REF_STRING (arg5 , ifrname );
1640
- ZEND_TRY_ASSIGN_REF_LONG(arg6, sll.sll_ifindex);
1739
+
1740
+ if (arg6 ) {
1741
+ ZEND_TRY_ASSIGN_REF_LONG (arg6 , sll .sll_ifindex );
1742
+ }
1641
1743
break ;
1642
- */
1643
1744
#endif
1644
1745
default :
1645
1746
zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
@@ -1661,7 +1762,10 @@ PHP_FUNCTION(socket_sendto)
1661
1762
struct sockaddr_in6 sin6 ;
1662
1763
#endif
1663
1764
#ifdef AF_PACKET
1664
- //struct sockaddr_ll sll;
1765
+ struct sockaddr_ll sll ;
1766
+ unsigned char halen ;
1767
+ int protoid ;
1768
+ socklen_t protoidlen = sizeof (protoid );
1665
1769
#endif
1666
1770
int retval ;
1667
1771
size_t buf_len ;
@@ -1694,6 +1798,15 @@ PHP_FUNCTION(socket_sendto)
1694
1798
RETURN_THROWS ();
1695
1799
}
1696
1800
1801
+ #ifdef AF_PACKET
1802
+ // ether header + payload
1803
+ // TODO dealing with SOCK_DGRAM
1804
+ if (php_sock -> type == AF_PACKET && len < 60 ) {
1805
+ zend_argument_value_error (3 , "must be at least 64 for AF_PACKET" );
1806
+ RETURN_THROWS ();
1807
+ }
1808
+ #endif
1809
+
1697
1810
switch (php_sock -> type ) {
1698
1811
case AF_UNIX :
1699
1812
memset (& s_un , 0 , sizeof (s_un ));
@@ -1738,23 +1851,33 @@ PHP_FUNCTION(socket_sendto)
1738
1851
break ;
1739
1852
#endif
1740
1853
#ifdef AF_PACKET
1741
- /*
1742
1854
case AF_PACKET :
1855
+ getsockopt (php_sock -> bsd_socket , SOL_SOCKET , SO_TYPE , (char * ) & protoid , & protoidlen );
1856
+
1857
+ // TODO: SOCK_DGRAM support
1858
+ if (protoid != SOCK_RAW ) {
1859
+ zend_argument_value_error (1 , "must be SOCK_RAW socket type" );
1860
+ RETURN_THROWS ();
1861
+ }
1743
1862
if (port_is_null ) {
1744
1863
zend_argument_value_error (6 , "cannot be null when the socket type is AF_PACKET" );
1745
1864
RETURN_THROWS ();
1746
1865
}
1747
1866
1867
+ halen = ZSTR_LEN (addr ) > ETH_ALEN ? ETH_ALEN : (unsigned char )ZSTR_LEN (addr );
1868
+
1748
1869
memset (& sll , 0 , sizeof (sll ));
1870
+ memcpy (sll .sll_addr , addr , halen );
1749
1871
sll .sll_family = AF_PACKET ;
1750
1872
sll .sll_ifindex = port ;
1873
+ sll .sll_halen = halen ;
1751
1874
1752
- retval = sendto(php_sock->bsd_socket, buf, ((size_t)len > buf_len) ? buf_len : (size_t)len, flags, (struct sockaddr *) &sin, sizeof(sin));
1875
+ // TODO allows to use more user friendly type to replace raw buffer usage
1876
+ retval = sendto (php_sock -> bsd_socket , buf , ((size_t )len > buf_len ) ? buf_len : (size_t )len , flags , (struct sockaddr * ) & sll , sizeof (sll ));
1753
1877
break ;
1754
- */
1755
1878
#endif
1756
1879
default :
1757
- zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, or AF_INET6" );
1880
+ zend_argument_value_error (1 , "must be one of AF_UNIX, AF_INET, AF_PACKET or AF_INET6" );
1758
1881
RETURN_THROWS ();
1759
1882
}
1760
1883
@@ -2880,8 +3003,6 @@ PHP_FUNCTION(socket_addrinfo_connect)
2880
3003
2881
3004
ai = Z_ADDRESS_INFO_P (arg1 );
2882
3005
2883
- PHP_ETH_PROTO_CHECK (ai -> addrinfo .ai_protocol , ai -> addrinfo .ai_family );
2884
-
2885
3006
object_init_ex (return_value , socket_ce );
2886
3007
php_sock = Z_SOCKET_P (return_value );
2887
3008
0 commit comments