Skip to content

Commit 5f50035

Browse files
committed
bug fixes and few more tests
1 parent 605c469 commit 5f50035

File tree

2 files changed

+115
-78
lines changed

2 files changed

+115
-78
lines changed

ext/sockets/sockets.c

Lines changed: 52 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,14 +1439,6 @@ PHP_FUNCTION(socket_bind)
14391439
#define ETH_SUB_CHECKLENGTH(a, lyr) \
14401440
do { \
14411441
if ((char *)ipdata + sizeof(a) < ZSTR_VAL(recv_buf) + slen) { \
1442-
zend_string_efree(recv_buf); \
1443-
Z_DELREF_P(zpayload); \
1444-
ZEND_TRY_ASSIGN_REF_VALUE(data, obj); \
1445-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname); \
1446-
if (index) { \
1447-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);\
1448-
} \
1449-
zend_value_error("invalid %s header", lyr); \
14501442
return FAILURE; \
14511443
} \
14521444
} while (0)
@@ -1464,7 +1456,8 @@ static zend_result php_socket_get_chunk(zend_string *dst, const zend_string *src
14641456
static zend_result php_socket_afpacket_add_tcp(unsigned char *ipdata, struct sockaddr_ll sll, char *ifrname, zend_string *recv_buf,
14651457
size_t slen, zval *szpayload, zval *zpayload, zval *obj, zval *data, zval *addr, zval *index, size_t headersize) {
14661458
struct tcphdr tcp;
1467-
ETH_SUB_CHECKLENGTH(tcp, "TCP");
1459+
if ((char *)ipdata + sizeof(tcp) < ZSTR_VAL(recv_buf) + slen)
1460+
return FAILURE;
14681461
memcpy(&tcp, ipdata, sizeof(tcp));
14691462
object_init_ex(szpayload, tcppacket_ce);
14701463
zend_update_property_long(Z_OBJCE_P(szpayload), Z_OBJ_P(szpayload), ZEND_STRL("srcPort"), ntohs(tcp.th_sport));
@@ -1479,7 +1472,8 @@ static zend_result php_socket_afpacket_add_tcp(unsigned char *ipdata, struct soc
14791472
static zend_result php_socket_afpacket_add_udp(unsigned char *ipdata, struct sockaddr_ll sll, char *ifrname, zend_string *recv_buf,
14801473
size_t slen, zval *szpayload, zval *zpayload, zval *obj, zval *data, zval *addr, zval *index, size_t headersize) {
14811474
struct udphdr udp;
1482-
ETH_SUB_CHECKLENGTH(udp, "UDP");
1475+
if ((char *)ipdata + sizeof(udp) < ZSTR_VAL(recv_buf) + slen)
1476+
return FAILURE;
14831477
memcpy(&udp, ipdata, sizeof(udp));
14841478
object_init_ex(szpayload, udppacket_ce);
14851479
zend_update_property_long(Z_OBJCE_P(szpayload), Z_OBJ_P(szpayload), ZEND_STRL("srcPort"), ntohs(udp.uh_sport));
@@ -1765,9 +1759,10 @@ PHP_FUNCTION(socket_recvfrom)
17651759
switch (protocol) {
17661760
case ETH_P_IP: {
17671761
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, sizeof(struct iphdr)) == FAILURE) {
1768-
zend_value_error("invalid ipv4 frame buffer length");
1762+
zval_ptr_dtor(&obj);
17691763
zend_string_release(dst_buf);
17701764
zend_string_efree(recv_buf);
1765+
zend_value_error("invalid ipv4 frame buffer length");
17711766
RETURN_THROWS();
17721767
}
17731768
payload = ((unsigned char *)ZSTR_VAL(dst_buf));
@@ -1777,17 +1772,9 @@ PHP_FUNCTION(socket_recvfrom)
17771772
size_t totalip = ntohs(ip.tot_len);
17781773

17791774
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, totalip)) {
1780-
ZVAL_NULL(&zpayload);
1781-
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1782-
zend_update_property_stringl(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf), ZSTR_LEN(recv_buf));
1775+
zval_ptr_dtor(&obj);
17831776
zend_string_release(dst_buf);
17841777
zend_string_efree(recv_buf);
1785-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1786-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1787-
1788-
if (index) {
1789-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1790-
}
17911778
zend_value_error("invalid transport header length");
17921779
RETURN_THROWS();
17931780
}
@@ -1804,74 +1791,71 @@ PHP_FUNCTION(socket_recvfrom)
18041791
switch (ip.protocol) {
18051792
case IPPROTO_TCP: {
18061793
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct tcphdr)) == FAILURE) {
1807-
zend_value_error("invalid tcp frame buffer length");
1794+
zval_ptr_dtor(&zpayload);
1795+
zval_ptr_dtor(&obj);
18081796
zend_string_release(dst_buf);
18091797
zend_string_efree(recv_buf);
1798+
zend_value_error("invalid tcp frame buffer length");
18101799
RETURN_THROWS();
18111800
}
18121801
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18131802
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, data, addr, index, ZSTR_LEN(dst_buf)) == FAILURE) {
1803+
zval_ptr_dtor(&zpayload);
1804+
zval_ptr_dtor(&obj);
18141805
zend_string_release(dst_buf);
18151806
zend_string_efree(recv_buf);
1807+
zend_value_error("invalid tcp frame buffer length");
18161808
RETURN_THROWS();
18171809
}
18181810
break;
18191811
}
18201812
case IPPROTO_UDP: {
18211813
if (php_socket_get_chunk(dst_buf, recv_buf, tlayer, sizeof(struct udphdr)) == FAILURE) {
1822-
zend_value_error("invalid udp frame buffer length");
1814+
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1815+
zend_update_property_stringl(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf), ZSTR_LEN(recv_buf));
1816+
Z_DELREF_P(&zpayload);
18231817
zend_string_release(dst_buf);
18241818
zend_string_efree(recv_buf);
1819+
zend_value_error("invalid udp frame buffer length");
18251820
RETURN_THROWS();
18261821
}
18271822
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18281823
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, data, addr, index, ZSTR_LEN(dst_buf)) == FAILURE) {
1824+
zval_ptr_dtor(&zpayload);
1825+
zval_ptr_dtor(&obj);
18291826
zend_string_release(dst_buf);
18301827
zend_string_efree(recv_buf);
1828+
zend_value_error("invalid udp frame buffer length");
18311829
RETURN_THROWS();
18321830
}
18331831
break;
18341832
}
18351833
default:
1836-
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1837-
zend_update_property_stringl(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf), ZSTR_LEN(recv_buf));
1838-
zend_string_efree(recv_buf);
1834+
zval_ptr_dtor(&zpayload);
1835+
zval_ptr_dtor(&obj);
18391836
zend_string_release(dst_buf);
1840-
Z_DELREF(zpayload);
1841-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1842-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1843-
1844-
if (index) {
1845-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1846-
}
1837+
zend_string_efree(recv_buf);
18471838
zend_value_error("unsupported ip header protocol");
18481839
RETURN_THROWS();
18491840
}
18501841
break;
18511842
}
18521843
case ETH_P_IPV6: {
18531844
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, sizeof(struct iphdr)) == FAILURE) {
1854-
zend_value_error("invalid ipv4 frame buffer length");
1845+
zval_ptr_dtor(&obj);
18551846
zend_string_release(dst_buf);
18561847
zend_string_efree(recv_buf);
1848+
zend_value_error("invalid ipv4 frame buffer length");
18571849
RETURN_THROWS();
18581850
}
18591851
payload = ((unsigned char *)ZSTR_VAL(dst_buf));
18601852
struct ipv6hdr ip;
18611853
memcpy(&ip, payload, sizeof(ip));
18621854
size_t totalip = sizeof(ip) + ip.payload_len;
18631855
if (totalip < slen) {
1864-
ZVAL_NULL(&zpayload);
1865-
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1866-
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
1867-
zend_string_efree(recv_buf);
1856+
zval_ptr_dtor(&obj);
18681857
zend_string_release(dst_buf);
1869-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1870-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1871-
1872-
if (index) {
1873-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1874-
}
1858+
zend_string_efree(recv_buf);
18751859
zend_value_error("invalid transport header length");
18761860
RETURN_THROWS();
18771861
}
@@ -1889,69 +1873,71 @@ PHP_FUNCTION(socket_recvfrom)
18891873
switch (ipprotocol) {
18901874
case IPPROTO_TCP: {
18911875
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(ip), sizeof(struct tcphdr)) == FAILURE) {
1892-
zend_value_error("invalid tcp frame buffer length");
1876+
zval_ptr_dtor(&zpayload);
1877+
zval_ptr_dtor(&obj);
18931878
zend_string_release(dst_buf);
18941879
zend_string_efree(recv_buf);
1880+
zend_value_error("invalid tcp frame buffer length");
18951881
RETURN_THROWS();
18961882
}
18971883
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
18981884
if (php_socket_afpacket_add_tcp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, data, addr, index, ZSTR_LEN(dst_buf)) == FAILURE) {
1885+
zval_ptr_dtor(&zpayload);
1886+
zval_ptr_dtor(&obj);
18991887
zend_string_release(dst_buf);
19001888
zend_string_efree(recv_buf);
1889+
zend_value_error("invalid tcp frame buffer length");
19011890
RETURN_THROWS();
19021891
}
19031892
break;
19041893
}
19051894
case IPPROTO_UDP: {
19061895
if (php_socket_get_chunk(dst_buf, recv_buf, sizeof(ip), sizeof(struct udphdr)) == FAILURE) {
1907-
zend_value_error("invalid udp frame buffer length");
1896+
zval_ptr_dtor(&zpayload);
1897+
zval_ptr_dtor(&obj);
19081898
zend_string_release(dst_buf);
19091899
zend_string_efree(recv_buf);
1900+
zend_value_error("invalid udp frame buffer length");
19101901
RETURN_THROWS();
19111902
}
19121903
unsigned char *ipdata = (unsigned char *)ZSTR_VAL(dst_buf);
19131904
if (php_socket_afpacket_add_udp(ipdata, sll, ifrname, recv_buf, slen, &szpayload, &zpayload, &obj, data, addr, data, ZSTR_LEN(dst_buf)) == FAILURE) {
1905+
zval_ptr_dtor(&zpayload);
1906+
zval_ptr_dtor(&obj);
19141907
zend_string_release(dst_buf);
19151908
zend_string_efree(recv_buf);
1909+
zend_value_error("invalid udp frame buffer length");
19161910
RETURN_THROWS();
19171911
}
19181912
break;
19191913
}
19201914
// TODO IPPROTO_ICMPV6 support
19211915
default:
1922-
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1923-
zend_update_property_stringl(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf), ZSTR_LEN(recv_buf));
1916+
zval_ptr_dtor(&zpayload);
1917+
zval_ptr_dtor(&obj);
19241918
zend_string_efree(recv_buf);
19251919
zend_string_release(dst_buf);
1926-
Z_DELREF(zpayload);
1927-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1928-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1929-
1930-
if (index) {
1931-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1932-
}
19331920
zend_value_error("unsupported ipv6 header protocol");
19341921
RETURN_THROWS();
19351922
}
19361923
break;
19371924
}
19381925
case ETH_P_LOOP: {
19391926
if (php_socket_get_chunk(dst_buf, recv_buf, ETH_HLEN, ETH_HLEN) == FAILURE) {
1940-
zend_value_error("invalid ethernet frame buffer length");
1927+
zval_ptr_dtor(&zpayload);
1928+
zval_ptr_dtor(&obj);
19411929
zend_string_efree(recv_buf);
19421930
zend_string_release(dst_buf);
1931+
zend_value_error("invalid ethernet frame buffer length");
19431932
RETURN_THROWS();
19441933
}
19451934
struct ethhdr innere;
19461935
payload = (unsigned char *)ZSTR_VAL(dst_buf);
19471936
if ((char *)payload + sizeof(innere) < ZSTR_VAL(recv_buf) + slen) {
1948-
zend_string_efree(recv_buf);
1937+
zval_ptr_dtor(&zpayload);
1938+
zval_ptr_dtor(&obj);
19491939
zend_string_release(dst_buf);
1950-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1951-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1952-
if (index) {
1953-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1954-
}
1940+
zend_string_efree(recv_buf);
19551941
zend_value_error("invalid ethernet loop header");
19561942
RETURN_THROWS();
19571943
}
@@ -1969,18 +1955,10 @@ PHP_FUNCTION(socket_recvfrom)
19691955
break;
19701956
}
19711957
default:
1972-
ZVAL_NULL(&zpayload);
1973-
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
1974-
zend_update_property_string(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf));
1975-
zend_string_efree(recv_buf);
1958+
zval_ptr_dtor(&zpayload);
1959+
zval_ptr_dtor(&obj);
19761960
zend_string_release(dst_buf);
1977-
1978-
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
1979-
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
1980-
1981-
if (index) {
1982-
ZEND_TRY_ASSIGN_REF_LONG(index, sll.sll_ifindex);
1983-
}
1961+
zend_string_efree(recv_buf);
19841962
zend_value_error("unsupported ethernet protocol");
19851963
RETURN_THROWS();
19861964
}
@@ -1990,8 +1968,8 @@ PHP_FUNCTION(socket_recvfrom)
19901968
zend_update_property(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("payload"), &zpayload);
19911969
zend_update_property_stringl(Z_OBJCE(obj), Z_OBJ(obj), ZEND_STRL("rawPacket"), ZSTR_VAL(recv_buf), ZSTR_LEN(recv_buf));
19921970
Z_DELREF(zpayload);
1971+
zend_string_release(dst_buf);
19931972
zend_string_efree(recv_buf);
1994-
zend_string_free(dst_buf);
19951973

19961974
ZEND_TRY_ASSIGN_REF_VALUE(data, &obj);
19971975
ZEND_TRY_ASSIGN_REF_STRING(addr, ifrname);
@@ -2062,7 +2040,7 @@ PHP_FUNCTION(socket_sendto)
20622040
// ether header + payload
20632041
// TODO dealing with SOCK_DGRAM
20642042
if (php_sock->type == AF_PACKET && len < 60) {
2065-
zend_argument_value_error(3, "must be at least 64 for AF_PACKET");
2043+
zend_argument_value_error(3, "must be at least 60 for AF_PACKET");
20662044
RETURN_THROWS();
20672045
}
20682046
#endif

ext/sockets/tests/socket_afpacket_error.phpt

Lines changed: 63 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ if (PHP_INT_SIZE != 8) {
2525
$v_bind = socket_bind($s_s, 'lo');
2626

2727
$payload = random_bytes(1024);
28-
$payload .= str_repeat("A", 46);
28+
$payload .= str_repeat("A", 1200);
2929

3030
$buf = pack("H12H12n", "ffffffffffff", "000000000000", 0x0806);
3131
$buf .= $payload;
@@ -86,6 +86,7 @@ if (PHP_INT_SIZE != 8) {
8686
} catch(\ValueError $e) {
8787
echo $e->getMessage(), PHP_EOL;
8888
}
89+
8990
socket_close($s_s);
9091
socket_close($s_c);
9192

@@ -150,15 +151,73 @@ if (PHP_INT_SIZE != 8) {
150151
var_dump(filter_var($rsp->payload->srcAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== null);
151152

152153

154+
$udp_hdr = pack('nnnn', 1024, 1025, "TEST", 4);
155+
156+
$buf = $ethhdr
157+
. $ipv6_first_4
158+
. $ipv6_payload_len
159+
. $ipv6_nexthdr
160+
. $ipv6_hop_limit
161+
. $src_ip
162+
. $dst_ip
163+
. $udp_hdr;
164+
165+
$buf .= str_repeat("\x00", max(0, 60 - strlen($buf)));
166+
167+
var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
168+
var_dump(socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr));
169+
170+
var_dump($rsp->ethProtocol == ETH_P_IPV6);
171+
var_dump(filter_var($rsp->payload->srcAddr, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6) !== null);
172+
173+
socket_close($s_s);
174+
socket_close($s_c);
175+
176+
$s_c = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
177+
$s_bind = socket_bind($s_c, 'lo');
178+
179+
$s_s = socket_create(AF_PACKET, SOCK_RAW, ETH_P_ALL);
180+
$v_bind = socket_bind($s_s, 'lo');
181+
182+
$payload = hex2bin(
183+
"4500" .
184+
"0028" .
185+
"0000" .
186+
"4000" .
187+
"4006" .
188+
"0000" .
189+
"7f000001" .
190+
"7f000001"
191+
) . str_repeat("A", 1024);
192+
193+
$buf = pack("H12H12n", "ffffffffffff", "000000000000", ETH_P_LOOP);
194+
$buf .= $payload;
195+
196+
var_dump(socket_sendto($s_s, $buf, strlen($buf), 0, "lo", 1));
197+
198+
try {
199+
socket_recvfrom($s_c, $rsp, strlen($buf), 0, $addr);
200+
} catch (\ValueError $e) {
201+
echo $e->getMessage(), PHP_EOL;
202+
}
203+
204+
205+
socket_close($s_s);
206+
socket_close($s_c);
153207
?>
154208
--EXPECTF--
155-
int(1084)
209+
int(%d)
156210
unsupported ethernet protocol
157211
int(60)
158212
invalid transport header length
159-
socket_sendto(): Argument #3 ($length) must be at least 64 for AF_PACKET
160-
invalid ethernet loop header
213+
socket_sendto(): Argument #3 ($length) must be at least 60 for AF_PACKET
161214
int(%d)
162215
int(%d)
163216
bool(true)
164217
bool(true)
218+
int(%d)
219+
int(%d)
220+
bool(true)
221+
bool(true)
222+
int(%d)
223+
invalid ethernet loop header

0 commit comments

Comments
 (0)