123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841 |
- /*
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Gustavo Lopes <cataphract@php.net> |
- +----------------------------------------------------------------------+
- */
- #ifdef HAVE_CONFIG_H
- #include "config.h"
- #endif
- #include "php.h"
- #include "php_network.h"
- #ifdef PHP_WIN32
- # include "windows_common.h"
- #else
- #include <sys/socket.h>
- #include <sys/ioctl.h>
- #include <net/if.h>
- #ifdef HAVE_SYS_SOCKIO_H
- #include <sys/sockio.h>
- #endif
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #endif
- #include "php_sockets.h"
- #include "multicast.h"
- #include "sockaddr_conv.h"
- #include "main/php_network.h"
- enum source_op {
- JOIN_SOURCE,
- LEAVE_SOURCE,
- BLOCK_SOURCE,
- UNBLOCK_SOURCE
- };
- static int _php_mcast_join_leave(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, unsigned int if_index, int join);
- #ifdef HAS_MCAST_EXT
- static int _php_mcast_source_op(php_socket *sock, int level, struct sockaddr *group, socklen_t group_len, struct sockaddr *source, socklen_t source_len, unsigned int if_index, enum source_op sop);
- #endif
- #ifdef RFC3678_API
- static int _php_source_op_to_rfc3678_op(enum source_op sop);
- #elif HAS_MCAST_EXT
- static const char *_php_source_op_to_string(enum source_op sop);
- static int _php_source_op_to_ipv4_op(enum source_op sop);
- #endif
- int php_string_to_if_index(const char *val, unsigned *out)
- {
- #if HAVE_IF_NAMETOINDEX
- unsigned int ind;
- ind = if_nametoindex(val);
- if (ind == 0) {
- php_error_docref(NULL, E_WARNING,
- "No interface with name \"%s\" could be found", val);
- return FAILURE;
- } else {
- *out = ind;
- return SUCCESS;
- }
- #else
- php_error_docref(NULL, E_WARNING,
- "This platform does not support looking up an interface by "
- "name, an integer interface index must be supplied instead");
- return FAILURE;
- #endif
- }
- static int php_get_if_index_from_zval(zval *val, unsigned *out)
- {
- int ret;
- if (Z_TYPE_P(val) == IS_LONG) {
- if (Z_LVAL_P(val) < 0 || (zend_ulong)Z_LVAL_P(val) > UINT_MAX) {
- zend_value_error("Index must be between 0 and %u", UINT_MAX);
- return FAILURE;
- }
- *out = Z_LVAL_P(val);
- ret = SUCCESS;
- } else {
- zend_string *tmp_str;
- zend_string *str = zval_get_tmp_string(val, &tmp_str);
- ret = php_string_to_if_index(ZSTR_VAL(str), out);
- zend_tmp_string_release(tmp_str);
- }
- return ret;
- }
- static int php_get_if_index_from_array(const HashTable *ht, const char *key,
- php_socket *sock, unsigned int *if_index)
- {
- zval *val;
- if ((val = zend_hash_str_find(ht, key, strlen(key))) == NULL) {
- *if_index = 0; /* default: 0 */
- return SUCCESS;
- }
- return php_get_if_index_from_zval(val, if_index);
- }
- static int php_get_address_from_array(const HashTable *ht, const char *key,
- php_socket *sock, php_sockaddr_storage *ss, socklen_t *ss_len)
- {
- zval *val;
- zend_string *str, *tmp_str;
- if ((val = zend_hash_str_find(ht, key, strlen(key))) == NULL) {
- zend_value_error("No key \"%s\" passed in optval", key);
- return FAILURE;
- }
- str = zval_get_tmp_string(val, &tmp_str);
- if (!php_set_inet46_addr(ss, ss_len, ZSTR_VAL(str), sock)) {
- zend_tmp_string_release(tmp_str);
- return FAILURE;
- }
- zend_tmp_string_release(tmp_str);
- return SUCCESS;
- }
- static int php_do_mcast_opt(php_socket *php_sock, int level, int optname, zval *arg4)
- {
- HashTable *opt_ht;
- unsigned int if_index;
- int retval;
- int (*mcast_req_fun)(php_socket *, int, struct sockaddr *, socklen_t,
- unsigned);
- #ifdef HAS_MCAST_EXT
- int (*mcast_sreq_fun)(php_socket *, int, struct sockaddr *, socklen_t,
- struct sockaddr *, socklen_t, unsigned);
- #endif
- switch (optname) {
- case PHP_MCAST_JOIN_GROUP:
- mcast_req_fun = &php_mcast_join;
- goto mcast_req_fun;
- case PHP_MCAST_LEAVE_GROUP:
- {
- mcast_req_fun = &php_mcast_leave;
- mcast_req_fun: ;
- php_sockaddr_storage group = {0};
- socklen_t glen;
- convert_to_array(arg4);
- opt_ht = Z_ARRVAL_P(arg4);
- if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
- &glen) == FAILURE) {
- return FAILURE;
- }
- if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
- &if_index) == FAILURE) {
- return FAILURE;
- }
- retval = mcast_req_fun(php_sock, level, (struct sockaddr*)&group,
- glen, if_index);
- break;
- }
- #ifdef HAS_MCAST_EXT
- case PHP_MCAST_BLOCK_SOURCE:
- mcast_sreq_fun = &php_mcast_block_source;
- goto mcast_sreq_fun;
- case PHP_MCAST_UNBLOCK_SOURCE:
- mcast_sreq_fun = &php_mcast_unblock_source;
- goto mcast_sreq_fun;
- case PHP_MCAST_JOIN_SOURCE_GROUP:
- mcast_sreq_fun = &php_mcast_join_source;
- goto mcast_sreq_fun;
- case PHP_MCAST_LEAVE_SOURCE_GROUP:
- {
- mcast_sreq_fun = &php_mcast_leave_source;
- mcast_sreq_fun: ;
- php_sockaddr_storage group = {0},
- source = {0};
- socklen_t glen,
- slen;
- convert_to_array(arg4);
- opt_ht = Z_ARRVAL_P(arg4);
- if (php_get_address_from_array(opt_ht, "group", php_sock, &group,
- &glen) == FAILURE) {
- return FAILURE;
- }
- if (php_get_address_from_array(opt_ht, "source", php_sock, &source,
- &slen) == FAILURE) {
- return FAILURE;
- }
- if (php_get_if_index_from_array(opt_ht, "interface", php_sock,
- &if_index) == FAILURE) {
- return FAILURE;
- }
- retval = mcast_sreq_fun(php_sock, level, (struct sockaddr*)&group,
- glen, (struct sockaddr*)&source, slen, if_index);
- break;
- }
- #endif
- default:
- php_error_docref(NULL, E_WARNING,
- "Unexpected option in php_do_mcast_opt (level %d, option %d). "
- "This is a bug.", level, optname);
- return FAILURE;
- }
- if (retval != 0) {
- if (retval != -2) { /* error, but message already emitted */
- PHP_SOCKET_ERROR(php_sock, "Unable to set socket option", errno);
- }
- return FAILURE;
- }
- return SUCCESS;
- }
- int php_do_setsockopt_ip_mcast(php_socket *php_sock,
- int level,
- int optname,
- zval *arg4)
- {
- unsigned int if_index;
- struct in_addr if_addr;
- void *opt_ptr;
- socklen_t optlen;
- unsigned char ipv4_mcast_ttl_lback;
- int retval;
- switch (optname) {
- case PHP_MCAST_JOIN_GROUP:
- case PHP_MCAST_LEAVE_GROUP:
- #ifdef HAS_MCAST_EXT
- case PHP_MCAST_BLOCK_SOURCE:
- case PHP_MCAST_UNBLOCK_SOURCE:
- case PHP_MCAST_JOIN_SOURCE_GROUP:
- case PHP_MCAST_LEAVE_SOURCE_GROUP:
- #endif
- if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) {
- return FAILURE;
- } else {
- return SUCCESS;
- }
- case IP_MULTICAST_IF:
- if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) {
- return FAILURE;
- }
- if (php_if_index_to_addr4(if_index, php_sock, &if_addr) == FAILURE) {
- return FAILURE;
- }
- opt_ptr = &if_addr;
- optlen = sizeof(if_addr);
- goto dosockopt;
- case IP_MULTICAST_LOOP:
- convert_to_boolean(arg4);
- ipv4_mcast_ttl_lback = (unsigned char) (Z_TYPE_P(arg4) == IS_TRUE);
- goto ipv4_loop_ttl;
- case IP_MULTICAST_TTL:
- convert_to_long(arg4);
- if (Z_LVAL_P(arg4) < 0L || Z_LVAL_P(arg4) > 255L) {
- zend_argument_value_error(4, "must be between 0 and 255");
- return FAILURE;
- }
- ipv4_mcast_ttl_lback = (unsigned char) Z_LVAL_P(arg4);
- ipv4_loop_ttl:
- opt_ptr = &ipv4_mcast_ttl_lback;
- optlen = sizeof(ipv4_mcast_ttl_lback);
- goto dosockopt;
- }
- return 1;
- dosockopt:
- retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
- if (retval != 0) {
- PHP_SOCKET_ERROR(php_sock, "Unable to set socket option", errno);
- return FAILURE;
- }
- return SUCCESS;
- }
- int php_do_setsockopt_ipv6_mcast(php_socket *php_sock,
- int level,
- int optname,
- zval *arg4)
- {
- unsigned int if_index;
- void *opt_ptr;
- socklen_t optlen;
- int ov;
- int retval;
- switch (optname) {
- case PHP_MCAST_JOIN_GROUP:
- case PHP_MCAST_LEAVE_GROUP:
- #ifdef HAS_MCAST_EXT
- case PHP_MCAST_BLOCK_SOURCE:
- case PHP_MCAST_UNBLOCK_SOURCE:
- case PHP_MCAST_JOIN_SOURCE_GROUP:
- case PHP_MCAST_LEAVE_SOURCE_GROUP:
- #endif
- if (php_do_mcast_opt(php_sock, level, optname, arg4) == FAILURE) {
- return FAILURE;
- } else {
- return SUCCESS;
- }
- case IPV6_MULTICAST_IF:
- if (php_get_if_index_from_zval(arg4, &if_index) == FAILURE) {
- return FAILURE;
- }
- opt_ptr = &if_index;
- optlen = sizeof(if_index);
- goto dosockopt;
- case IPV6_MULTICAST_LOOP:
- convert_to_boolean(arg4);
- ov = (int) Z_TYPE_P(arg4) == IS_TRUE;
- goto ipv6_loop_hops;
- case IPV6_MULTICAST_HOPS:
- convert_to_long(arg4);
- if (Z_LVAL_P(arg4) < -1L || Z_LVAL_P(arg4) > 255L) {
- zend_argument_value_error(4, "must be between -1 and 255");
- return FAILURE;
- }
- ov = (int) Z_LVAL_P(arg4);
- ipv6_loop_hops:
- opt_ptr = &ov;
- optlen = sizeof(ov);
- goto dosockopt;
- }
- return 1; /* not handled */
- dosockopt:
- retval = setsockopt(php_sock->bsd_socket, level, optname, opt_ptr, optlen);
- if (retval != 0) {
- PHP_SOCKET_ERROR(php_sock, "Unable to set socket option", errno);
- return FAILURE;
- }
- return SUCCESS;
- }
- int php_mcast_join(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- unsigned int if_index)
- {
- return _php_mcast_join_leave(sock, level, group, group_len, if_index, 1);
- }
- int php_mcast_leave(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- unsigned int if_index)
- {
- return _php_mcast_join_leave(sock, level, group, group_len, if_index, 0);
- }
- #ifdef HAS_MCAST_EXT
- int php_mcast_join_source(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- struct sockaddr *source,
- socklen_t source_len,
- unsigned int if_index)
- {
- return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, JOIN_SOURCE);
- }
- int php_mcast_leave_source(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- struct sockaddr *source,
- socklen_t source_len,
- unsigned int if_index)
- {
- return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, LEAVE_SOURCE);
- }
- int php_mcast_block_source(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- struct sockaddr *source,
- socklen_t source_len,
- unsigned int if_index)
- {
- return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, BLOCK_SOURCE);
- }
- int php_mcast_unblock_source(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- struct sockaddr *source,
- socklen_t source_len,
- unsigned int if_index)
- {
- return _php_mcast_source_op(sock, level, group, group_len, source, source_len, if_index, UNBLOCK_SOURCE);
- }
- #endif /* HAS_MCAST_EXT */
- static int _php_mcast_join_leave(
- php_socket *sock,
- int level,
- struct sockaddr *group, /* struct sockaddr_in/sockaddr_in6 */
- socklen_t group_len,
- unsigned int if_index,
- int join)
- {
- #ifdef RFC3678_API
- struct group_req greq = {0};
- memcpy(&greq.gr_group, group, group_len);
- assert(greq.gr_group.ss_family != 0); /* the caller has set this */
- greq.gr_interface = if_index;
- return setsockopt(sock->bsd_socket, level,
- join ? MCAST_JOIN_GROUP : MCAST_LEAVE_GROUP, (char*)&greq,
- sizeof(greq));
- #else
- if (sock->type == AF_INET) {
- struct ip_mreq mreq;
- struct in_addr addr;
- memset(&mreq, 0, sizeof(struct ip_mreq));
- assert(group_len == sizeof(struct sockaddr_in));
- if (if_index != 0) {
- if (php_if_index_to_addr4(if_index, sock, &addr) ==
- FAILURE)
- return -2; /* failure, but notice already emitted */
- mreq.imr_interface = addr;
- } else {
- mreq.imr_interface.s_addr = htonl(INADDR_ANY);
- }
- mreq.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
- return setsockopt(sock->bsd_socket, level,
- join ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP, (char*)&mreq,
- sizeof(mreq));
- }
- #if HAVE_IPV6
- else if (sock->type == AF_INET6) {
- struct ipv6_mreq mreq;
- memset(&mreq, 0, sizeof(struct ipv6_mreq));
- assert(group_len == sizeof(struct sockaddr_in6));
- mreq.ipv6mr_multiaddr = ((struct sockaddr_in6*)group)->sin6_addr;
- mreq.ipv6mr_interface = if_index;
- return setsockopt(sock->bsd_socket, level,
- join ? IPV6_JOIN_GROUP : IPV6_LEAVE_GROUP, (char*)&mreq,
- sizeof(mreq));
- }
- #endif
- else {
- zend_value_error("Option %s is inapplicable to this socket type",
- join ? "MCAST_JOIN_GROUP" : "MCAST_LEAVE_GROUP");
- return -2;
- }
- #endif
- }
- #ifdef HAS_MCAST_EXT
- static int _php_mcast_source_op(
- php_socket *sock,
- int level,
- struct sockaddr *group,
- socklen_t group_len,
- struct sockaddr *source,
- socklen_t source_len,
- unsigned int if_index,
- enum source_op sop)
- {
- #ifdef RFC3678_API
- struct group_source_req gsreq = {0};
- memcpy(&gsreq.gsr_group, group, group_len);
- assert(gsreq.gsr_group.ss_family != 0);
- memcpy(&gsreq.gsr_source, source, source_len);
- assert(gsreq.gsr_source.ss_family != 0);
- gsreq.gsr_interface = if_index;
- return setsockopt(sock->bsd_socket, level,
- _php_source_op_to_rfc3678_op(sop), (char*)&gsreq, sizeof(gsreq));
- #else
- if (sock->type == AF_INET) {
- struct ip_mreq_source mreqs = {0};
- struct in_addr addr;
- mreqs.imr_multiaddr = ((struct sockaddr_in*)group)->sin_addr;
- mreqs.imr_sourceaddr = ((struct sockaddr_in*)source)->sin_addr;
- assert(group_len == sizeof(struct sockaddr_in));
- assert(source_len == sizeof(struct sockaddr_in));
- if (if_index != 0) {
- if (php_if_index_to_addr4(if_index, sock, &addr) ==
- FAILURE)
- return -2; /* failure, but notice already emitted */
- mreqs.imr_interface = addr;
- } else {
- mreqs.imr_interface.s_addr = htonl(INADDR_ANY);
- }
- return setsockopt(sock->bsd_socket, level,
- _php_source_op_to_ipv4_op(sop), (char*)&mreqs, sizeof(mreqs));
- }
- #if HAVE_IPV6
- else if (sock->type == AF_INET6) {
- php_error_docref(NULL, E_WARNING,
- "This platform does not support %s for IPv6 sockets",
- _php_source_op_to_string(sop));
- return -2;
- }
- #endif
- else {
- php_error_docref(NULL, E_WARNING,
- "Option %s is inapplicable to this socket type",
- _php_source_op_to_string(sop));
- return -2;
- }
- #endif
- }
- #if RFC3678_API
- static int _php_source_op_to_rfc3678_op(enum source_op sop)
- {
- switch (sop) {
- case JOIN_SOURCE:
- return MCAST_JOIN_SOURCE_GROUP;
- case LEAVE_SOURCE:
- return MCAST_LEAVE_SOURCE_GROUP;
- case BLOCK_SOURCE:
- return MCAST_BLOCK_SOURCE;
- case UNBLOCK_SOURCE:
- return MCAST_UNBLOCK_SOURCE;
- }
- assert(0);
- return 0;
- }
- #else
- static const char *_php_source_op_to_string(enum source_op sop)
- {
- switch (sop) {
- case JOIN_SOURCE:
- return "MCAST_JOIN_SOURCE_GROUP";
- case LEAVE_SOURCE:
- return "MCAST_LEAVE_SOURCE_GROUP";
- case BLOCK_SOURCE:
- return "MCAST_BLOCK_SOURCE";
- case UNBLOCK_SOURCE:
- return "MCAST_UNBLOCK_SOURCE";
- }
- assert(0);
- return "";
- }
- static int _php_source_op_to_ipv4_op(enum source_op sop)
- {
- switch (sop) {
- case JOIN_SOURCE:
- return IP_ADD_SOURCE_MEMBERSHIP;
- case LEAVE_SOURCE:
- return IP_DROP_SOURCE_MEMBERSHIP;
- case BLOCK_SOURCE:
- return IP_BLOCK_SOURCE;
- case UNBLOCK_SOURCE:
- return IP_UNBLOCK_SOURCE;
- }
- assert(0);
- return 0;
- }
- #endif
- #endif /* HAS_MCAST_EXT */
- #ifdef PHP_WIN32
- int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr)
- {
- MIB_IPADDRTABLE *addr_table;
- ULONG size;
- DWORD retval;
- DWORD i;
- (void) php_sock; /* not necessary */
- if (if_index == 0) {
- out_addr->s_addr = INADDR_ANY;
- return SUCCESS;
- }
- size = 4 * (sizeof *addr_table);
- addr_table = emalloc(size);
- retry:
- retval = GetIpAddrTable(addr_table, &size, 0);
- if (retval == ERROR_INSUFFICIENT_BUFFER) {
- efree(addr_table);
- addr_table = emalloc(size);
- goto retry;
- }
- if (retval != NO_ERROR) {
- efree(addr_table);
- php_error_docref(NULL, E_WARNING,
- "GetIpAddrTable failed with error %lu", retval);
- return FAILURE;
- }
- for (i = 0; i < addr_table->dwNumEntries; i++) {
- MIB_IPADDRROW r = addr_table->table[i];
- if (r.dwIndex == if_index) {
- out_addr->s_addr = r.dwAddr;
- efree(addr_table);
- return SUCCESS;
- }
- }
- efree(addr_table);
- php_error_docref(NULL, E_WARNING,
- "No interface with index %u was found", if_index);
- return FAILURE;
- }
- int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index)
- {
- MIB_IPADDRTABLE *addr_table;
- ULONG size;
- DWORD retval;
- DWORD i;
- (void) php_sock; /* not necessary */
- if (addr->s_addr == INADDR_ANY) {
- *if_index = 0;
- return SUCCESS;
- }
- size = 4 * (sizeof *addr_table);
- addr_table = emalloc(size);
- retry:
- retval = GetIpAddrTable(addr_table, &size, 0);
- if (retval == ERROR_INSUFFICIENT_BUFFER) {
- efree(addr_table);
- addr_table = emalloc(size);
- goto retry;
- }
- if (retval != NO_ERROR) {
- efree(addr_table);
- php_error_docref(NULL, E_WARNING,
- "GetIpAddrTable failed with error %lu", retval);
- return FAILURE;
- }
- for (i = 0; i < addr_table->dwNumEntries; i++) {
- MIB_IPADDRROW r = addr_table->table[i];
- if (r.dwAddr == addr->s_addr) {
- *if_index = r.dwIndex;
- efree(addr_table);
- return SUCCESS;
- }
- }
- efree(addr_table);
- {
- char addr_str[17] = {0};
- inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
- php_error_docref(NULL, E_WARNING,
- "The interface with IP address %s was not found", addr_str);
- }
- return FAILURE;
- }
- #else
- int php_if_index_to_addr4(unsigned if_index, php_socket *php_sock, struct in_addr *out_addr)
- {
- struct ifreq if_req;
- if (if_index == 0) {
- out_addr->s_addr = INADDR_ANY;
- return SUCCESS;
- }
- #if !defined(ifr_ifindex) && (defined(ifr_index) || defined(__HAIKU__))
- #define ifr_ifindex ifr_index
- #endif
- #if defined(SIOCGIFNAME)
- if_req.ifr_ifindex = if_index;
- if (ioctl(php_sock->bsd_socket, SIOCGIFNAME, &if_req) == -1) {
- #elif defined(HAVE_IF_INDEXTONAME)
- if (if_indextoname(if_index, if_req.ifr_name) == NULL) {
- #else
- #error Neither SIOCGIFNAME nor if_indextoname are available
- #endif
- php_error_docref(NULL, E_WARNING,
- "Failed obtaining address for interface %u: error %d", if_index, errno);
- return FAILURE;
- }
- if (ioctl(php_sock->bsd_socket, SIOCGIFADDR, &if_req) == -1) {
- php_error_docref(NULL, E_WARNING,
- "Failed obtaining address for interface %u: error %d", if_index, errno);
- return FAILURE;
- }
- memcpy(out_addr, &((struct sockaddr_in *) &if_req.ifr_addr)->sin_addr,
- sizeof *out_addr);
- return SUCCESS;
- }
- int php_add4_to_if_index(struct in_addr *addr, php_socket *php_sock, unsigned *if_index)
- {
- struct ifconf if_conf = {0};
- char *buf = NULL,
- *p;
- int size = 0,
- lastsize = 0;
- size_t entry_len;
- if (addr->s_addr == INADDR_ANY) {
- *if_index = 0;
- return SUCCESS;
- }
- for(;;) {
- size += 5 * sizeof(struct ifreq);
- buf = ecalloc(size, 1);
- if_conf.ifc_len = size;
- if_conf.ifc_buf = buf;
- if (ioctl(php_sock->bsd_socket, SIOCGIFCONF, (char*)&if_conf) == -1 &&
- (errno != EINVAL || lastsize != 0)) {
- php_error_docref(NULL, E_WARNING,
- "Failed obtaining interfaces list: error %d", errno);
- goto err;
- }
- if (if_conf.ifc_len == lastsize)
- /* not increasing anymore */
- break;
- else {
- lastsize = if_conf.ifc_len;
- efree(buf);
- buf = NULL;
- }
- }
- for (p = if_conf.ifc_buf;
- p < ((char *)if_conf.ifc_buf) + if_conf.ifc_len;
- p += entry_len) {
- /* p may be misaligned on macos. */
- struct ifreq cur_req;
- memcpy(&cur_req, p, sizeof(struct ifreq));
- #ifdef HAVE_SOCKADDR_SA_LEN
- entry_len = cur_req.ifr_addr.sa_len + sizeof(cur_req.ifr_name);
- #else
- /* if there's no sa_len, assume the ifr_addr field is a sockaddr */
- entry_len = sizeof(struct sockaddr) + sizeof(cur_req.ifr_name);
- #endif
- entry_len = MAX(entry_len, sizeof(cur_req));
- if ((((struct sockaddr*)&cur_req.ifr_addr)->sa_family == AF_INET) &&
- (((struct sockaddr_in*)&cur_req.ifr_addr)->sin_addr.s_addr ==
- addr->s_addr)) {
- #if defined(SIOCGIFINDEX)
- if (ioctl(php_sock->bsd_socket, SIOCGIFINDEX, (char*)&cur_req)
- == -1) {
- #elif defined(HAVE_IF_NAMETOINDEX)
- unsigned index_tmp;
- if ((index_tmp = if_nametoindex(cur_req.ifr_name)) == 0) {
- #else
- #error Neither SIOCGIFINDEX nor if_nametoindex are available
- #endif
- php_error_docref(NULL, E_WARNING,
- "Error converting interface name to index: error %d",
- errno);
- goto err;
- } else {
- #if defined(SIOCGIFINDEX)
- *if_index = cur_req.ifr_ifindex;
- #else
- *if_index = index_tmp;
- #endif
- efree(buf);
- return SUCCESS;
- }
- }
- }
- {
- char addr_str[17] = {0};
- inet_ntop(AF_INET, addr, addr_str, sizeof(addr_str));
- php_error_docref(NULL, E_WARNING,
- "The interface with IP address %s was not found", addr_str);
- }
- err:
- if (buf != NULL)
- efree(buf);
- return FAILURE;
- }
- #endif
|