From: Boris Lytochkin Date: Sat, 20 Aug 2011 16:10:48 +0000 (+0000) Subject: merge from trunk two commits: X-Git-Tag: php-5.4.0beta1~398 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=cbcf729a3061a80b779da969a08e61b8f7af6d08;p=php merge from trunk two commits: Adding IPv6 support (FR #42918) more code coverage --- diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c index 28613e7415..fd179b4359 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -28,6 +28,7 @@ #endif #include "php.h" +#include "main/php_network.h" #include "ext/standard/info.h" #include "php_snmp.h" @@ -1075,9 +1076,13 @@ static int php_snmp_parse_oid(int st, struct objid_query *objid_query, zval **oi */ static int netsnmp_session_init(php_snmp_session **session_p, int version, char *hostname, char *community, int timeout, int retries TSRMLS_DC) { - int remote_port = SNMP_PORT; php_snmp_session *session; char *pptr; + char buf[MAX_NAME_LEN]; + int force_ipv6 = FALSE; + int n; + struct sockaddr **psal; + struct sockaddr **res; *session_p = (php_snmp_session *)emalloc(sizeof(php_snmp_session)); session = *session_p; @@ -1085,25 +1090,86 @@ static int netsnmp_session_init(php_snmp_session **session_p, int version, char php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed allocating session"); return (-1); } + memset(session, 0, sizeof(php_snmp_session)); + + strlcpy(buf, hostname, sizeof(buf)); snmp_sess_init(session); session->version = version; + session->remote_port = SNMP_PORT; session->peername = emalloc(MAX_NAME_LEN); - if(session->peername == NULL) { + if (session->peername == NULL) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "emalloc() failed while copying hostname"); - netsnmp_session_free(&session); return (-1); } + *(session->peername) = '\0'; /* Reading the hostname and its optional non-default port number */ - strlcpy(session->peername, hostname, MAX_NAME_LEN); - if ((pptr = strchr(session->peername, ':'))) { - remote_port = strtol(pptr + 1, NULL, 0); + if (*hostname == '[') { /* IPv6 address */ + force_ipv6 = TRUE; + hostname++; + if ((pptr = strchr(hostname, ']'))) { + if (pptr[1] == ':') { + session->remote_port = atoi(pptr + 2); + } + *pptr = '\0'; + } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "mailformed IPv6 address, closing square bracket missing"); + return (-1); + } + } else { /* IPv4 address */ + if ((pptr = strchr(hostname, ':'))) { + session->remote_port = atoi(pptr + 1); + *pptr = '\0'; + } + } + + /* since Net-SNMP library requires 'udp6:' prefix for all IPv6 addresses (in FQDN form too) we need to + perform possible name resolution before running any SNMP queries */ + if ((n = php_network_getaddresses(hostname, SOCK_DGRAM, &psal, NULL TSRMLS_CC)) == 0) { /* some resover error */ + /* warnings sent, bailing out */ + return (-1); + } + + res = psal; + while (n-- > 0) { + pptr = session->peername; +#if HAVE_GETADDRINFO && HAVE_IPV6 && HAVE_INET_NTOP + if (force_ipv6 && (*res)->sa_family != AF_INET6) { + res++; + continue; + } + if ((*res)->sa_family == AF_INET6) { + strcpy(session->peername, "udp6:"); + pptr = session->peername + strlen(session->peername); + inet_ntop((*res)->sa_family, &(((struct sockaddr_in6*)(*res))->sin6_addr), pptr, MAX_NAME_LEN); + } else if ((*res)->sa_family == AF_INET) { + inet_ntop((*res)->sa_family, &(((struct sockaddr_in*)(*res))->sin_addr), pptr, MAX_NAME_LEN); + } else { + res++; + continue; + } +#else + if (res->sa_family != AF_INET) { + res++; + continue; + } + strcat(pptr, inet_ntoa(res)); +#endif + break; + } + + if (strlen(session->peername) == 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown failure while resolving '%s'", buf); + return (-1); } + /* XXX FIXME + There should be check for non-empty session->peername! + */ - session->remote_port = remote_port; + php_network_freeaddresses(psal); if (version == SNMP_VERSION_3) { /* Setting the security name. */ diff --git a/ext/snmp/tests/README b/ext/snmp/tests/README index d87d17ad1b..74258ec27f 100644 --- a/ext/snmp/tests/README +++ b/ext/snmp/tests/README @@ -9,7 +9,9 @@ To enable these tests, you must have : ** How to test ** You need to give credentials with environment vars if default ones are not sutable (see snmp_include.inc for more info): -SNMP_HOSTNAME : IP or IP:PORT to connect to +SNMP_HOSTNAME : IPv4 of remote SNMP agent +SNMP_HOSTNAME : IPv6 or remote SNMP agent +SNMP_PORT : SNMP port for queries SNMP_COMMUNITY : community name SNMP_COMMUNITY_WRITE : community used for write tests (snmpset()). SNMP_MIBDIR : Directory containing MIBS @@ -26,6 +28,7 @@ On Linux/FreeBSD ###### Config file ##### rocommunity public 127.0.0.1 +rocommunity6 public ::1 rwcommunity private 127.0.0.1 Do not enable them - being set here they make appropriate OID switch into r/o diff --git a/ext/snmp/tests/generic_timeout_error.phpt b/ext/snmp/tests/generic_timeout_error.phpt index 0f5101a439..c333a0d20b 100644 --- a/ext/snmp/tests/generic_timeout_error.phpt +++ b/ext/snmp/tests/generic_timeout_error.phpt @@ -15,8 +15,13 @@ snmp_set_quick_print(false); snmp_set_valueretrieval(SNMP_VALUE_PLAIN); var_dump(snmpget($hostname, 'timeout_community_432', '.1.3.6.1.2.1.1.1.0', $timeout, $retries)); +var_dump(snmpget($hostname, 'timeout_community_432', array('.1.3.6.1.2.1.1.1.0'), $timeout, $retries)); ?> --EXPECTF-- Warning: snmpget(): No response from %s in %s on line %d bool(false) + +Warning: snmpget(): No response from %s in %s on line %d +bool(false) + diff --git a/ext/snmp/tests/ipv6.phpt b/ext/snmp/tests/ipv6.phpt new file mode 100644 index 0000000000..78119d1575 --- /dev/null +++ b/ext/snmp/tests/ipv6.phpt @@ -0,0 +1,24 @@ +--TEST-- +IPv6 support +--CREDITS-- +Boris Lytochkin +--SKIPIF-- + +--FILE-- + +--EXPECTF-- +%unicode|string%(%d) "%s" diff --git a/ext/snmp/tests/snmp-object-errno-errstr.phpt b/ext/snmp/tests/snmp-object-errno-errstr.phpt index 923fb856e0..427a754b08 100644 --- a/ext/snmp/tests/snmp-object-errno-errstr.phpt +++ b/ext/snmp/tests/snmp-object-errno-errstr.phpt @@ -42,6 +42,7 @@ $session->setSecurity('authPriv', 'MD5', $auth_pass, 'AES', $priv_pass); var_dump(@$session->get('.1.3.6.1.2.1.1.1.0')); var_dump($session->getErrno() == SNMP::ERRNO_GENERIC); var_dump($session->getError()); +var_dump(@$session->get(array('.1.3.6.1.2.1.1.1.0'))); $session->close(); ?> --EXPECTF-- @@ -61,3 +62,4 @@ SNMP::ERRNO_GENERIC bool(false) bool(true) %string|unicode%(%d) "Fatal error: Unknown user name" +bool(false) diff --git a/ext/snmp/tests/snmp_include.inc b/ext/snmp/tests/snmp_include.inc index c91499078d..caa0721890 100644 --- a/ext/snmp/tests/snmp_include.inc +++ b/ext/snmp/tests/snmp_include.inc @@ -6,9 +6,11 @@ requests and 'private' community for write requests. Default timeout is 1000ms and there will be one request performed. */ -$hostname = getenv('SNMP_HOSTNAME') ? getenv('SNMP_HOSTNAME') : '127.0.0.1'; +$hostname4 = getenv('SNMP_HOSTNAME') ? getenv('SNMP_HOSTNAME') : '127.0.0.1'; +$hostname6 = getenv('SNMP_HOSTNAME6') ? getenv('SNMP_HOSTNAME6') : '::1'; $port = getenv('SNMP_PORT') ? getenv('SNMP_PORT') : '161'; -$hostname .= ":$port"; +$hostname = "$hostname4:$port"; +$hostname6_port = "[$hostname6]:$port"; $community = getenv('SNMP_COMMUNITY') ? getenv('SNMP_COMMUNITY') : 'public'; $communityWrite = getenv('SNMP_COMMUNITY_WRITE')? getenv('SNMP_COMMUNITY_WRITE'):'private'; diff --git a/ext/snmp/tests/wrong_hostname.phpt b/ext/snmp/tests/wrong_hostname.phpt index e0bfa8a54d..4ab087e41f 100644 --- a/ext/snmp/tests/wrong_hostname.phpt +++ b/ext/snmp/tests/wrong_hostname.phpt @@ -18,5 +18,5 @@ var_dump(snmpget('192.168..6.1', 'community', '.1.3.6.1.2.1.1.1.0', $timeout, $r ?> --EXPECTF-- -Warning: snmpget(): Could not open snmp connection: Unknown host (192.168..6.1) (%s) in %s on line %d +Warning: snmpget(): php_network_getaddresses: getaddrinfo failed: hostname nor servname provided, or not known in %s on line %d bool(false)