/* * * (c) Copyright 1989 OPEN SOFTWARE FOUNDATION, INC. * (c) Copyright 1989 HEWLETT-PACKARD COMPANY * (c) Copyright 1989 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) 1989 by ** Hewlett-Packard Company, Palo Alto, Ca. & ** Digital Equipment Corporation, Maynard, Mass. ** ** ** 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 ** Linux. ** ** - taken from ipnaf_bsd.c ** ** ** */ #include #include #include #include #include /* Bizarre hack for HP-UX ia64 where a system header * makes reference to a kernel-only data structure */ #if defined(__hpux) && defined(__ia64) union mpinfou {}; #endif #include #include /* Hack to ensure we actually get a definition of ioctl on AIX */ #if defined(_AIX) && defined(_BSD) int ioctl(int d, int request, ...); #endif #include #ifdef HAVE_SYS_SOCKIO_H #include /* Not just Linux */ #endif /*********************************************************************** * * Internal prototypes and typedefs. */ INTERNAL boolean get_addr _DCE_PROTOTYPE_ (( rpc_socket_t /*sock*/, rpc_addr_p_t /*ip_addr*/, rpc_addr_p_t /*netmask_addr*/, rpc_addr_p_t /*broadcast_addr*/ )); INTERNAL boolean get_broadcast_addr _DCE_PROTOTYPE_ (( rpc_socket_t /*sock*/, rpc_addr_p_t /*ip_addr*/, rpc_addr_p_t /*netmask_addr*/, rpc_addr_p_t /*broadcast_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: 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 ( rpc_socket_t sock ATTRIBUTE_UNUSED, rpc_addr_p_t ip_addr ATTRIBUTE_UNUSED, rpc_addr_p_t netmask_addr ATTRIBUTE_UNUSED, rpc_addr_p_t broadcast_addr ATTRIBUTE_UNUSED ) { return true; } INTERNAL boolean get_addr_noloop ( rpc_socket_t sock ATTRIBUTE_UNUSED, rpc_addr_p_t _ip_addr, rpc_addr_p_t netmask_addr ATTRIBUTE_UNUSED, rpc_addr_p_t broadcast_addr ATTRIBUTE_UNUSED ) { rpc_ip_addr_p_t ip_addr = (rpc_ip_addr_p_t) _ip_addr; if (((unsigned char*) &ip_addr->sa.sin_addr)[0] == 127) { return false; } 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 sock, 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; socklen_t _slen; int err = 0; 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. */ _slen = (socklen_t) sizeof (rpc_ip_addr_t); loc_ip_addr.len = sizeof(loc_ip_addr.sa); err = rpc__socket_inq_endpoint (sock, (rpc_addr_p_t) &loc_ip_addr); if (err) { *status = -1; /* !!! */ return; } if (loc_ip_addr.sa.sin_addr.s_addr == 0) { err = rpc__socket_enum_ifaces(sock, get_addr_noloop, rpc_addr_vec, NULL, NULL); if (err != RPC_C_SOCKET_OK) { *status = -1; 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; } *status = rpc_s_ok; return; } 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 ( rpc_socket_t sock ATTRIBUTE_UNUSED, rpc_addr_p_t _ip_addr ATTRIBUTE_UNUSED, rpc_addr_p_t netmask_addr ATTRIBUTE_UNUSED, rpc_addr_p_t broadcast_addr ) { if (broadcast_addr == NULL) { return false; } #if !defined(BROADCAST_NEEDS_LOOPBACK) && !defined(USE_LOOPBACK) rpc_ip_addr_p_t ip_addr = (rpc_ip_addr_p_t) _ip_addr; if (((unsigned char*) &ip_addr->sa.sin_addr)[0] == 127) { return false; } #endif 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 ATTRIBUTE_UNUSED, rpc_protseq_id_t protseq_id, rpc_addr_vector_p_t *rpc_addr_vec, unsigned32 *status ) { rpc_socket_t sock = RPC_SOCKET_INVALID; int err = RPC_C_SOCKET_OK; CODING_ERROR (status); err = rpc__socket_open(protseq_id, NULL, &sock); if (err) { *status = -1; goto done; } err = rpc__socket_enum_ifaces (sock, get_broadcast_addr, NULL, NULL, rpc_addr_vec); if (err) { *status = -1; goto done; } done: if (sock != RPC_SOCKET_INVALID) { RPC_SOCKET_CLOSE(sock); } return; } /* **++ ** ** 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 #ifdef _DCE_PROTO_ ( unsigned32 *status ) #else (status) unsigned32 *status; #endif { rpc_socket_t sock = RPC_SOCKET_INVALID; unsigned32 i; rpc_addr_vector_p_t rpc_addr_vec = NULL; rpc_addr_vector_p_t netmask_addr_vec = NULL; int err; CODING_ERROR (status); err = rpc__socket_open(RPC_C_PROTSEQ_ID_NCADG_IP_UDP, NULL, &sock); if (err) { *status = rpc_s_cant_create_socket;; goto error; } err = rpc__socket_enum_ifaces(sock, get_addr, &rpc_addr_vec, &netmask_addr_vec, NULL); if (err) { *status = -1; goto error; } /* * 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 error; } 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 error; } 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 } done: if (sock != RPC_SOCKET_INVALID) { RPC_SOCKET_CLOSE(sock); } return; error: 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); } goto done; } /* **++ ** ** 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 #ifdef _DCE_PROTO_ ( rpc_addr_p_t rpc_addr, unsigned32 *status ) #else (rpc_addr, status) rpc_addr_p_t rpc_addr; unsigned32 *status; #endif { 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 #ifdef _DCE_PROTO_ ( rpc_addr_p_t rpc_addr, unsigned32 *status ) #else (rpc_addr, status) rpc_addr_p_t rpc_addr; unsigned32 *status; #endif { 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; }