/* * Copyright (c) 2010 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Inc. ("Apple") nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Portions of this software have been released under the following terms: * * (c) Copyright 1989-1993 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989-1993 HEWLETT-PACKARD COMPANY * (c) Copyright 1989-1993 DIGITAL EQUIPMENT CORPORATION * * To anyone who acknowledges that this file is provided "AS IS" * without any express or implied warranty: * permission to use, copy, modify, and distribute this file for any * purpose is hereby granted without fee, provided that the above * copyright notices and this notice appears in all source code copies, * and that none of the names of Open Software Foundation, Inc., Hewlett- * Packard Company or Digital Equipment Corporation be used * in advertising or publicity pertaining to distribution of the software * without specific, written prior permission. Neither Open Software * Foundation, Inc., Hewlett-Packard Company nor Digital * Equipment Corporation makes any representations about the suitability * of this software for any purpose. * * Copyright (c) 2007, Novell, Inc. All rights reserved. * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of Novell Inc. nor the names of its contributors * may be used to endorse or promote products derived from this * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * @APPLE_LICENSE_HEADER_END@ */ /* ** ** NAME ** ** ipnaf_bsd ** ** FACILITY: ** ** Remote Procedure Call (RPC) ** ** ABSTRACT: ** ** This module contains routines specific to the Internet Protocol, ** the Internet Network Address Family extension service, and the ** Berkeley Unix system. ** ** */ #include #include #include #include #include #include #include /*********************************************************************** * * Internal prototypes and typedefs. */ typedef boolean (*enumerate_fn_p_t) (( int /* in */ /*desc*/, struct ifreq /* in */ * /*ifr*/, unsigned32 /* in */ /*if_flags*/, struct sockaddr /* in */ * /*if_addr*/, rpc_ip_addr_p_t /* out */ /*ip_addr*/, rpc_ip_addr_p_t /* out */ /*netmask_addr*/ ); INTERNAL void enumerate_interfaces ( rpc_protseq_id_t /*protseq_id*/, rpc_socket_t /*desc*/, enumerate_fn_p_t /*efun*/, rpc_addr_vector_p_t * /*rpc_addr_vec*/, rpc_addr_vector_p_t * /*netmask_addr_vec*/, unsigned32 * /*st*/ ); INTERNAL boolean get_addr ( int /*desc*/, struct ifreq * /*ifr*/, unsigned32 /*if_flags*/, struct sockaddr * /*if_addr*/, rpc_ip_addr_p_t /*ip_addr*/, rpc_ip_addr_p_t /*netmask_addr*/ ); INTERNAL boolean get_broadcast_addr ( int /*desc*/, struct ifreq * /*ifr*/, unsigned32 /*if_flags*/, struct sockaddr * /*if_addr*/, rpc_ip_addr_p_t /*ip_addr*/, rpc_ip_addr_p_t /*netmask_addr*/ ); #ifndef NO_SPRINTF # define RPC__IP_NETWORK_SPRINTF sprintf #else # define RPC__IP_NETWORK_SPRINTF rpc__ip_network_sprintf #endif typedef struct { unsigned32 num_elt; struct { unsigned32 addr; unsigned32 netmask; } elt[1]; } rpc_ip_s_addr_vector_t, *rpc_ip_s_addr_vector_p_t; INTERNAL rpc_ip_s_addr_vector_p_t local_ip_addr_vec = NULL; /* **++ ** ** ROUTINE NAME: enumerate_interfaces ** ** SCOPE: INTERNAL - declared locally ** ** DESCRIPTION: ** ** Return a vector of IP RPC addresses. Note that this function is ** shared by both "rpc__ip_desc_inq_addr" and "rpc__ip_get_broadcast" ** so that we have to have only one copy of all the gore (ioctl's) ** associated with inquiring about network interfaces. This routine ** filters out all network interface information that doesn't correspond ** to up, non-loopback, IP-addressed network interfaces. The supplied ** procedure pointer (efun) does the rest of the work. ** ** ** INPUTS: ** ** protseq_id Protocol Sequence ID representing a particular ** Network Address Family, its Transport Protocol, ** and type. ** ** desc Descriptor, indicating a socket that has been ** created on the local operating platform. ** ** efun Procedure pointer supplied to "do the rest of the work". ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** rpc_addr_vec Returned vector of RPC addresses. ** ** netmask_addr_vec Returned vector of netmask RPC addresses. ** ** status A value indicating the status of the routine. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** SIDE EFFECTS: none ** **-- **/ #ifdef _SOCKADDR_LEN /* * Note that in the world of BSD 4.4, the struct ifreq's returned * from SIOCGIFCONF are *varying length*, but a minimum of 32 bytes. * * This has some interesting implications on how to parse the result * from SIOCGIFCONF. */ #endif INTERNAL void enumerate_interfaces ( rpc_protseq_id_t protseq_id, rpc_socket_t desc, enumerate_fn_p_t efun, rpc_addr_vector_p_t *rpc_addr_vec, rpc_addr_vector_p_t *netmask_addr_vec, unsigned32 *status ) { rpc_ip_addr_p_t ip_addr; int n_ifs; unsigned char buf[1024]; struct ifconf ifc; struct ifreq *ifr, *last_ifr; struct ifreq ifreq; short if_flags; struct sockaddr if_addr; int i; #ifdef _SOCKADDR_LEN int prev_size; #else const int prev_size = sizeof(struct ifreq) ; #endif rpc_ip_addr_p_t netmask_addr = NULL; CODING_ERROR (status); /* * Get the list of network interfaces. */ ifc.ifc_len = sizeof (buf); ifc.ifc_buf = (caddr_t) buf; ifconf_again: if (ioctl (desc, (int) SIOCGIFCONF, (caddr_t) &ifc) < 0) { if (errno == EINTR) { goto ifconf_again; } *status = -2; /* !!! */ return; } /* * Figure out how many interfaces there must be and allocate an * RPC address vector with the appropriate number of elements. * (We may ask for a few too many in case some of the interfaces * are uninteresting.) */ n_ifs = ifc.ifc_len / sizeof (struct ifreq); RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("%d bytes of ifreqs, ifreq is %d bytes\n", ifc.ifc_len, sizeof(struct ifreq))); #ifdef MAX_DEBUG if (RPC_DBG2(rpc_e_dbg_general, 15)) { int i; char msgbuf[128]; for (i=0; ilen = 0; } /* * Go through the interfaces and get the info associated with them. */ (*rpc_addr_vec)->len = 0; last_ifr = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); for (i=0, ifr = ifc.ifc_req; ifr < last_ifr ; i++, ifr = (struct ifreq *)(( (char *) ifr ) + prev_size)) { #ifdef _SOCKADDR_LEN prev_size = sizeof (struct ifreq) - sizeof(struct sockaddr) + ifr->ifr_addr.sa_len ; #endif RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("interface %d: %s\n", i, ifr->ifr_name)); /* * Get the interface's flags. If the flags say that the interface * is not up or is the loopback interface, skip it. Do the * SIOCGIFFLAGS on a copy of the ifr so we don't lose the original * contents of the ifr. (ifr's are unions that hold only one * of the interesting interface attributes [address, flags, etc.] * at a time.) */ memcpy(&ifreq, ifr, sizeof(ifreq)); ifflags_again: if (ioctl(desc, SIOCGIFFLAGS, &ifreq) < 0) { RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("SIOCGIFFLAGS returned errno %d\n", errno)); if (errno == EINTR) { goto ifflags_again; } continue; } if_flags = ifreq.ifr_flags; /* Copy out the flags */ RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("flags are %x\n", if_flags)); /* * Ignore interfaces which are not 'up'. */ if ((if_flags & IFF_UP) == 0) continue; /* * Get the addressing stuff for this interface. */ #ifdef NO_SIOCGIFADDR /* * Note that some systems do not return the address for the * interface given. However the ifr array elts contained in * the ifc block returned from the SIOCGIFCONF ioctl above already * contains the correct addresses. So these systems should define * NO_SIOCGIFADDR in their platform specific include file. */ if_addr = ifr->ifr_addr; #else /* * Do the SIOCGIFADDR on a copy of the ifr. See above. */ memcpy(&ifreq, ifr, sizeof(ifreq)); ifaddr_again: if (ioctl(desc, SIOCGIFADDR, &ifreq) < 0) { RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("SIOCGIFADDR returned errno %d\n", errno)); if (errno == EINTR) { goto ifaddr_again; } *status = -4; goto FREE_IT; } memcpy (&if_addr, &ifr->ifr_addr, sizeof(struct sockaddr)); #endif /* NO_SIOCGIFADDR */ /* * If this isn't an Internet-family address, ignore it. */ if (if_addr.sa_family != AF_INET) { RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("AF %d not INET\n", if_addr.sa_family)); continue; } /* * Allocate and fill in an IP RPC address for this interface. */ RPC_MEM_ALLOC ( ip_addr, rpc_ip_addr_p_t, sizeof (rpc_ip_addr_t), RPC_C_MEM_RPC_ADDR, RPC_C_MEM_WAITOK); if (ip_addr == NULL) { *status = rpc_s_no_memory; goto FREE_IT; } ip_addr->rpc_protseq_id = protseq_id; ip_addr->len = sizeof (struct sockaddr_in); if (netmask_addr_vec != NULL) { RPC_MEM_ALLOC ( netmask_addr, rpc_ip_addr_p_t, sizeof (rpc_ip_addr_t), RPC_C_MEM_RPC_ADDR, RPC_C_MEM_WAITOK); if (netmask_addr == NULL) { *status = rpc_s_no_memory; RPC_MEM_FREE (ip_addr, RPC_C_MEM_RPC_ADDR); goto FREE_IT; } netmask_addr->rpc_protseq_id = protseq_id; netmask_addr->len = sizeof (struct sockaddr_in); } /* * Call out to do any final filtering and get the desired IP address * for this interface. If the callout function returns false, we * forget about this interface. */ if ((*efun) (desc, ifr, if_flags, &if_addr, ip_addr, netmask_addr) == false) { RPC_MEM_FREE (ip_addr, RPC_C_MEM_RPC_ADDR); if (netmask_addr != NULL) RPC_MEM_FREE (netmask_addr, RPC_C_MEM_RPC_ADDR); continue; } RPC_SOCKET_FIX_ADDRLEN(ip_addr); (*rpc_addr_vec)->addrs[(*rpc_addr_vec)->len++] = (rpc_addr_p_t) ip_addr; if (netmask_addr_vec != NULL && netmask_addr != NULL) (*netmask_addr_vec)->addrs[(*netmask_addr_vec)->len++] = (rpc_addr_p_t) netmask_addr; } if ((*rpc_addr_vec)->len == 0) { *status = -5; /* !!! */ goto FREE_IT; } *status = rpc_s_ok; return; FREE_IT: for (i = 0; i < (*rpc_addr_vec)->len; i++) { RPC_MEM_FREE ((*rpc_addr_vec)->addrs[i], RPC_C_MEM_RPC_ADDR); } RPC_MEM_FREE (*rpc_addr_vec, RPC_C_MEM_RPC_ADDR_VEC); if (netmask_addr_vec != NULL) { for (i = 0; i < (*netmask_addr_vec)->len; i++) { RPC_MEM_FREE ((*netmask_addr_vec)->addrs[i], RPC_C_MEM_RPC_ADDR); } RPC_MEM_FREE (*netmask_addr_vec, RPC_C_MEM_RPC_ADDR_VEC); } } /* **++ ** ** ROUTINE NAME: get_addr ** ** SCOPE: INTERNAL - declared locally ** ** DESCRIPTION: ** ** This function is called from "rpc__ip_desc_inq_addr" via ** "enumerate_interfaces". See comments in "enumerate_interfaces" for ** details. ** ** ** INPUTS: none ** ** desc Socket being used for ioctl's. ** ** ifr Structure describing the interface. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** ip_addr ** ** netmask_addr netmask address ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** result true => we generated up an address for this interface ** false => we didn't. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL boolean get_addr ( int desc, struct ifreq *ifr, unsigned32 if_flags, struct sockaddr *if_addr, rpc_ip_addr_p_t ip_addr, rpc_ip_addr_p_t netmask_addr ) { struct ifreq ifreq; if (netmask_addr == NULL) { if ((if_flags & IFF_LOOPBACK) != 0) { return (false); } memcpy (&ip_addr->sa, if_addr, sizeof(struct sockaddr_in)); return (true); } else { memcpy (&ip_addr->sa, if_addr, sizeof(struct sockaddr_in)); /* * Inquire the interface's netmask address. */ ifreq = *ifr; ifnetaddr_again: if (ioctl(desc, (int) SIOCGIFNETMASK, &ifreq) == -1) { if (errno == EINTR) { goto ifnetaddr_again; } return (false); } memcpy (&netmask_addr->sa, &ifreq.ifr_addr, sizeof(struct sockaddr_in)); return (true); } } /* **++ ** ** ROUTINE NAME: rpc__ip_desc_inq_addr ** ** SCOPE: PRIVATE - declared in ipnaf.h ** ** DESCRIPTION: ** ** Receive a socket descriptor which is queried to obtain family, endpoint ** and network address. If this information appears valid for an IP ** address, space is allocated for an RPC address which is initialized ** with the information obtained from the socket. The address indicating ** the created RPC address is returned in rpc_addr. ** ** INPUTS: ** ** protseq_id Protocol Sequence ID representing a particular ** Network Address Family, its Transport Protocol, ** and type. ** ** desc Descriptor, indicating a socket that has been ** created on the local operating platform. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** rpc_addr_vec ** ** status A value indicating the status of the routine. ** ** rpc_s_ok The call was successful. ** ** rpc_s_no_memory Call to malloc failed to allocate memory. ** ** rpc_s_cant_inq_socket Attempt to get info about socket failed. ** ** Any of the RPC Protocol Service status codes. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE void rpc__ip_desc_inq_addr ( rpc_protseq_id_t protseq_id, rpc_socket_t desc, rpc_addr_vector_p_t *rpc_addr_vec, unsigned32 *status ) { rpc_ip_addr_p_t ip_addr; rpc_ip_addr_t loc_ip_addr; unsigned16 i; CODING_ERROR (status); /* * Do a "getsockname" into a local IP RPC address. If the network * address part of the result is non-zero, then the socket must be * bound to a particular IP address and we can just return a RPC * address vector with that one address (and endpoint) in it. * Otherwise, we have to enumerate over all the local network * interfaces the local host has and construct an RPC address for * each one of them. */ loc_ip_addr.len = sizeof (rpc_ip_addr_t); RPC_SOCKET_FIX_ADDRLEN(&loc_ip_addr); if (getsockname (desc, (struct sockaddr *)&loc_ip_addr.sa, (int *)&loc_ip_addr.len) < 0) { *status = -1; /* !!! */ return; } RPC_SOCKET_FIX_ADDRLEN(&loc_ip_addr); if (loc_ip_addr.sa.sin_addr.s_addr == 0) { enumerate_interfaces (protseq_id, desc, get_addr, rpc_addr_vec, NULL, status); if (*status != rpc_s_ok) { return; } for (i = 0; i < (*rpc_addr_vec)->len; i++) { ((rpc_ip_addr_p_t) (*rpc_addr_vec)->addrs[i])->sa.sin_port = loc_ip_addr.sa.sin_port; } } else { RPC_MEM_ALLOC ( ip_addr, rpc_ip_addr_p_t, sizeof (rpc_ip_addr_t), RPC_C_MEM_RPC_ADDR, RPC_C_MEM_WAITOK); if (ip_addr == NULL) { *status = rpc_s_no_memory; return; } RPC_MEM_ALLOC ( *rpc_addr_vec, rpc_addr_vector_p_t, sizeof **rpc_addr_vec, RPC_C_MEM_RPC_ADDR_VEC, RPC_C_MEM_WAITOK); if (*rpc_addr_vec == NULL) { RPC_MEM_FREE (ip_addr, RPC_C_MEM_RPC_ADDR); *status = rpc_s_no_memory; return; } ip_addr->rpc_protseq_id = protseq_id; ip_addr->len = sizeof (struct sockaddr_in); ip_addr->sa = loc_ip_addr.sa; (*rpc_addr_vec)->len = 1; (*rpc_addr_vec)->addrs[0] = (rpc_addr_p_t) ip_addr; *status = rpc_s_ok; return; } } /* **++ ** ** ROUTINE NAME: get_broadcast_addr ** ** SCOPE: INTERNAL - declared locally ** ** DESCRIPTION: ** ** This function is called from "rpc__ip_get_broadcast" via ** "enumerate_interfaces". See comments in "enumerate_interfaces" for ** details. ** ** ** INPUTS: none ** ** desc Socket being used for ioctl's. ** ** ifr Structure describing the interface. ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** ip_addr ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** result true => we generated up an address for this interface ** false => we didn't. ** ** SIDE EFFECTS: none ** **-- **/ INTERNAL boolean get_broadcast_addr ( int desc, struct ifreq *ifr, unsigned32 if_flags, struct sockaddr *if_addr, rpc_ip_addr_p_t ip_addr, rpc_ip_addr_p_t netmask_addr ) { struct ifreq ifreq; /* * If the interface's flags say this isn't a broadcast interface, * or isn't up, ignore it. */ if ((if_flags & IFF_BROADCAST) == 0 || (if_flags & IFF_UP) == 0) { return (false); } #ifndef BROADCAST_NEEDS_LOOPBACK /* * #define BROADCAST_NEEDS_LOOPBACK in case you need to broadcast * over the loopback interface to see your own broadcasts. */ if ((if_flags & IFF_LOOPBACK) != 0) { return (false); } #endif /* * Inquire the interface's broadcast address. */ ifreq = *ifr; ifbrdaddr_again: if (ioctl(desc, (int) SIOCGIFBRDADDR, &ifreq) < 0) { if (errno == EINTR) { goto ifbrdaddr_again; } return (false); } memcpy (&ip_addr->sa, &ifreq.ifr_broadaddr, sizeof(struct sockaddr_in)); RPC_SOCKET_FIX_ADDRLEN(ip_addr); return (true); } /* **++ ** ** ROUTINE NAME: rpc__ip_get_broadcast ** ** SCOPE: PRIVATE - EPV declared in ipnaf.h ** ** DESCRIPTION: ** ** Return a vector of RPC addresses that represent all the address ** required so that sending on all of them results in broadcasting on ** all the local network interfaces. ** ** ** INPUTS: ** ** naf_id Network Address Family ID serves ** as index into EPV for IP routines. ** ** rpc_protseq_id ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** rpc_addr_vec ** ** status A value indicating the status of the routine. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE void rpc__ip_get_broadcast ( rpc_naf_id_t naf_id, rpc_protseq_id_t protseq_id, rpc_addr_vector_p_t *rpc_addr_vec, unsigned32 *status ) { int desc; CODING_ERROR (status); /* * Open a socket to pass to "enumerate_interface". */ desc = socket(AF_INET, SOCK_DGRAM, 0); if (desc < 0) { *status = -7; /* !!! */ return; } enumerate_interfaces (protseq_id, desc, get_broadcast_addr, rpc_addr_vec, NULL, status); close(desc); } /* **++ ** ** ROUTINE NAME: rpc__ip_init_local_addr_vec ** ** SCOPE: PRIVATE - declared in ipnaf.h ** ** DESCRIPTION: ** ** Initialize the local address vectors. ** ** ** INPUTS: none ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: none ** ** SIDE EFFECTS: ** ** Update local_ip_addr_vec ** **-- **/ PRIVATE void rpc__ip_init_local_addr_vec ( unsigned32 *status ) { int desc; unsigned32 lstatus; unsigned32 i; rpc_addr_vector_p_t rpc_addr_vec = NULL; rpc_addr_vector_p_t netmask_addr_vec = NULL; CODING_ERROR (status); /* * Open a socket to pass to "enumerate_interface". */ desc = socket(AF_INET, SOCK_DGRAM, 0); if (desc < 0) { *status = rpc_s_cant_create_socket; /* !!! */ return; } enumerate_interfaces (rpc_c_protseq_id_ncadg_ip_udp, desc, get_addr, &rpc_addr_vec, &netmask_addr_vec, status); close(desc); if (*status != rpc_s_ok) { return; } /* * Do some sanity check. */ if (rpc_addr_vec == NULL || netmask_addr_vec == NULL || rpc_addr_vec->len != netmask_addr_vec->len || rpc_addr_vec->len == 0) { RPC_DBG_GPRINTF(("(rpc__ip_init_local_addr_vec) no local address\n")); *status = rpc_s_no_addrs; goto free_rpc_addrs; } RPC_MEM_ALLOC ( local_ip_addr_vec, rpc_ip_s_addr_vector_p_t, (sizeof *local_ip_addr_vec) + ((rpc_addr_vec->len - 1) * (sizeof (local_ip_addr_vec->elt[0]))), RPC_C_MEM_UTIL, RPC_C_MEM_WAITOK); if (local_ip_addr_vec == NULL) { *status = rpc_s_no_memory; goto free_rpc_addrs; } local_ip_addr_vec->num_elt = rpc_addr_vec->len; for (i = 0; i < rpc_addr_vec->len; i++) { local_ip_addr_vec->elt[i].addr = ((rpc_ip_addr_p_t) rpc_addr_vec->addrs[i])->sa.sin_addr.s_addr; local_ip_addr_vec->elt[i].netmask = ((rpc_ip_addr_p_t) netmask_addr_vec->addrs[i])->sa.sin_addr.s_addr; #ifdef DEBUG if (RPC_DBG2(rpc_e_dbg_general, 10)) { char buff[16], mbuff[16]; unsigned8 *p, *mp; p = (unsigned8 *) &(local_ip_addr_vec->elt[i].addr); mp = (unsigned8 *) &(local_ip_addr_vec->elt[i].netmask); RPC__IP_NETWORK_SPRINTF(buff, "%d.%d.%d.%d", UC(p[0]), UC(p[1]), UC(p[2]), UC(p[3])); RPC__IP_NETWORK_SPRINTF(mbuff, "%d.%d.%d.%d", UC(mp[0]), UC(mp[1]), UC(mp[2]), UC(mp[3])); RPC_DBG_PRINTF(rpc_e_dbg_general, 10, ("(rpc__ip_init_local_addr_vec) local network [%s] netmask [%s]\n", buff, mbuff)); } #endif } free_rpc_addrs: if (rpc_addr_vec != NULL) { for (i = 0; i < rpc_addr_vec->len; i++) { RPC_MEM_FREE (rpc_addr_vec->addrs[i], RPC_C_MEM_RPC_ADDR); } RPC_MEM_FREE (rpc_addr_vec, RPC_C_MEM_RPC_ADDR_VEC); } if (netmask_addr_vec != NULL) { for (i = 0; i < netmask_addr_vec->len; i++) { RPC_MEM_FREE (netmask_addr_vec->addrs[i], RPC_C_MEM_RPC_ADDR); } RPC_MEM_FREE (netmask_addr_vec, RPC_C_MEM_RPC_ADDR_VEC); } return; } /* **++ ** ** ROUTINE NAME: rpc__ip_is_local_network ** ** SCOPE: PRIVATE - declared in ipnaf.h ** ** DESCRIPTION: ** ** Return a boolean value to indicate if the given RPC address is on ** the same IP subnet. ** ** ** INPUTS: ** ** rpc_addr The address that forms the path of interest ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** result true => the address is on the same subnet. ** false => not. ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE boolean32 rpc__ip_is_local_network ( rpc_addr_p_t rpc_addr, unsigned32 *status ) { rpc_ip_addr_p_t ip_addr = (rpc_ip_addr_p_t) rpc_addr; unsigned32 addr1; unsigned32 addr2; unsigned32 i; CODING_ERROR (status); if (rpc_addr == NULL) { *status = rpc_s_invalid_arg; return false; } *status = rpc_s_ok; if (local_ip_addr_vec == NULL) { /* * We should call rpc__ip_init_local_addr_vec() here. But, it * requires the mutex lock for local_ip_addr_vec. For now just return * false. */ return false; } /* * Compare addresses. */ for (i = 0; i < local_ip_addr_vec->num_elt; i++) { if (ip_addr->sa.sin_family != AF_INET) { continue; } addr1 = ip_addr->sa.sin_addr.s_addr & local_ip_addr_vec->elt[i].netmask; addr2 = local_ip_addr_vec->elt[i].addr & local_ip_addr_vec->elt[i].netmask; if (addr1 == addr2) { return true; } } return false; } /* **++ ** ** ROUTINE NAME: rpc__ip_is_local_addr ** ** SCOPE: PRIVATE - declared in ipnaf.h ** ** DESCRIPTION: ** ** Return a boolean value to indicate if the given RPC address is the ** the local IP address. ** ** ** INPUTS: ** ** rpc_addr The address that forms the path of interest ** ** INPUTS/OUTPUTS: none ** ** OUTPUTS: ** ** status A value indicating the status of the routine. ** ** IMPLICIT INPUTS: none ** ** IMPLICIT OUTPUTS: none ** ** FUNCTION VALUE: ** ** result true => the address is local. ** false => not. ** ** SIDE EFFECTS: none ** **-- **/ PRIVATE boolean32 rpc__ip_is_local_addr ( rpc_addr_p_t rpc_addr, unsigned32 *status ) { rpc_ip_addr_p_t ip_addr = (rpc_ip_addr_p_t) rpc_addr; unsigned32 i; CODING_ERROR (status); if (rpc_addr == NULL) { *status = rpc_s_invalid_arg; return false; } *status = rpc_s_ok; if (local_ip_addr_vec == NULL) { /* * We should call rpc__ip_init_local_addr_vec() here. But, it * requires the mutex lock for local_ip_addr_vec. For now just return * false. */ return false; } /* * Compare addresses. */ for (i = 0; i < local_ip_addr_vec->num_elt; i++) { if (ip_addr->sa.sin_family != AF_INET) { continue; } if (ip_addr->sa.sin_addr.s_addr == local_ip_addr_vec->elt[i].addr) { return true; } } return false; }