summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <pollita@php.net>2017-03-07 11:27:46 -0800
committerSara Golemon <pollita@php.net>2017-03-07 12:10:53 -0800
commitbab0b99f376dac9170ac81382a5ed526938d595a (patch)
tree25a62afa850ec87c43eb1c0b0cd4fa9578cde6aa
parent549a30d2cd7756abc5f5116dfebe217098ade5c5 (diff)
downloadphp-git-bab0b99f376dac9170ac81382a5ed526938d595a.tar.gz
Detect invalid port in xp_socket parse ip address
For historical reasons, fsockopen() accepts the port and hostname separately: fsockopen('127.0.0.1', 80) However, with the introdcution of stream transports in PHP 4.3, it became possible to include the port in the hostname specifier: fsockopen('127.0.0.1:80') Or more formally: fsockopen('tcp://127.0.0.1:80') Confusing results when these two forms are combined, however. fsockopen('127.0.0.1:80', 443) results in fsockopen() attempting to connect to '127.0.0.1:80:443' which any reasonable stack would consider invalid. Unfortunately, PHP parses the address looking for the first colon (with special handling for IPv6, don't worry) and calls atoi() from there. atoi() in turn, simply stops parsing at the first non-numeric character and returns the value so far. The end result is that the explicitly supplied port is treated as ignored garbage, rather than producing an error. This diff replaces atoi() with strtol() and inspects the stop character. If additional "garbage" of any kind is found, it fails and returns an error.
-rw-r--r--ext/standard/tests/streams/parseip-001.phpt37
-rw-r--r--main/streams/xp_socket.c29
2 files changed, 55 insertions, 11 deletions
diff --git a/ext/standard/tests/streams/parseip-001.phpt b/ext/standard/tests/streams/parseip-001.phpt
new file mode 100644
index 0000000000..594756db6b
--- /dev/null
+++ b/ext/standard/tests/streams/parseip-001.phpt
@@ -0,0 +1,37 @@
+--TEST--
+Use of double-port in fsockopen()
+--FILE--
+<?php
+
+$try = [
+ '127.0.0.1:80',
+ 'tcp://127.0.0.1:80',
+ '[::1]:80',
+ 'tcp://[::1]:80',
+ 'localhost:80',
+ 'tcp://localhost:80',
+];
+
+foreach ($try as $addr) {
+ echo "== $addr ==\n";
+ var_dump(@fsockopen($addr, 81, $errno, $errstr), $errstr);
+}
+--EXPECTF--
+== 127.0.0.1:80 ==
+bool(false)
+string(41) "Failed to parse address "127.0.0.1:80:81""
+== tcp://127.0.0.1:80 ==
+bool(false)
+string(41) "Failed to parse address "127.0.0.1:80:81""
+== [::1]:80 ==
+bool(false)
+string(37) "Failed to parse address "[::1]:80:81""
+== tcp://[::1]:80 ==
+bool(false)
+string(37) "Failed to parse address "[::1]:80:81""
+== localhost:80 ==
+bool(false)
+string(41) "Failed to parse address "localhost:80:81""
+== tcp://localhost:80 ==
+bool(false)
+string(41) "Failed to parse address "localhost:80:81"" \ No newline at end of file
diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c
index 701a993ccc..3ff64787aa 100644
--- a/main/streams/xp_socket.c
+++ b/main/streams/xp_socket.c
@@ -571,37 +571,44 @@ static inline char *parse_ip_address_ex(const char *str, size_t str_len, int *po
char *host = NULL;
#ifdef HAVE_IPV6
- char *p;
-
if (*(str) == '[' && str_len > 1) {
/* IPV6 notation to specify raw address with port (i.e. [fe80::1]:80) */
- p = memchr(str + 1, ']', str_len - 2);
+ char *p = memchr(str + 1, ']', str_len - 2), *e = NULL;
if (!p || *(p + 1) != ':') {
if (get_err) {
*err = strpprintf(0, "Failed to parse IPv6 address \"%s\"", str);
}
return NULL;
}
- *portno = atoi(p + 2);
+ *portno = strtol(p + 2, &e, 10);
+ if (e && *e) {
+ if (get_err) {
+ *err = strpprintf(0, "Failed to parse address \"%s\"", str);
+ }
+ return NULL;
+ }
return estrndup(str + 1, p - str - 1);
}
#endif
+
if (str_len) {
colon = memchr(str, ':', str_len - 1);
} else {
colon = NULL;
}
+
if (colon) {
- *portno = atoi(colon + 1);
- host = estrndup(str, colon - str);
- } else {
- if (get_err) {
- *err = strpprintf(0, "Failed to parse address \"%s\"", str);
+ char *e = NULL;
+ *portno = strtol(colon + 1, &e, 10);
+ if (!e || !*e) {
+ return estrndup(str, colon - str);
}
- return NULL;
}
- return host;
+ if (get_err) {
+ *err = strpprintf(0, "Failed to parse address \"%s\"", str);
+ }
+ return NULL;
}
static inline char *parse_ip_address(php_stream_xport_param *xparam, int *portno)