The Perl Toolchain Summit 2025 Needs You: You can help 🙏 Learn more

/* ******************************************************************** *
* ni_util.c version 0.01 1-12-09 *
* *
* COPYRIGHT 2008-2009 Michael Robinton <michael@bizsystems.com> *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of either: *
* *
* a) the GNU General Public License as published by the Free *
* Software Foundation; either version 2, or (at your option) any *
* later version, or *
* *
* b) the "Artistic License" which comes with this distribution. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either *
* the GNU General Public License or the Artistic License for more *
* details. *
* *
* You should have received a copy of the Artistic License with this *
* distribution, in the file named "Artistic". If not, I'll be glad *
* to provide one. *
* *
* You should also have received a copy of the GNU General Public *
* License along with this program in the file named "Copying". If not, *
* write to the *
* *
* Free Software Foundation, Inc. *
* 59 Temple Place, Suite 330 *
* Boston, MA 02111-1307, USA *
* *
* or visit their web page on the internet at: *
* *
* ******************************************************************** */
#include "localconf.h"
/* duplicate allocate memory and return pointer **** memory must be freed */
void *
ni_memdup(void * memp, int size)
{
void * newmp;
if ((newmp = malloc(size)) == NULL) {
errno = ENOMEM;
return NULL;
}
return memcpy(newmp,memp,size);
}
/* two functions to conditionally close and reopen an ifconf socket
*
* if fd is < 0 it is ignored
* af is modified if required
*/
int
ni_clos_reopn_dgrm(int fd, u_int af)
{
if (fd >= 0)
close(fd);
af == AF_UNSPEC ? AF_INET : af;
return socket(af,SOCK_DGRAM,0);
}
/* **************************************************** *
* provide _SIZEOF_ADDR_IFREQ(ifr) equivalent *
* that will cover our use of in6_ifreq, lifreq *
* **************************************************** */
#ifdef _SIZEOF_ADDR_IFREQ
int
ni_SIZEOF_ADDR_IFREQ(struct ifreq * ifrp,struct sockaddr * sa,int size)
{
struct ifreq ifr;
memcpy(&ifr,ifrp,sizeof(struct ifreq));
return _SIZEOF_ADDR_IFREQ(ifr);
}
#endif
/* **************************************************** *
* on systems with embedded scope, get it *
* and correct the bits in the addrsess *
* **************************************************** */
#ifdef LOCAL_SIZEOF_SOCKADDR_IN6
u_int
ni_get_scopeid(struct sockaddr_in6 * sin6)
{
unsigned int scopeid = 0;
# ifdef __KAME__
if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
scopeid = ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
}
# elif defined HAVE_SIN6_SCOPEID
scopeid = sin6->sin6_scopeid;
# endif
return scopeid;
}
#endif
/* **************************************************** *
* generate a netmask from a prefix length *
* **************************************************** */
void
ni_plen2mask(void * in_addr, int plen, int sizeofaddr)
{
char * mask = in_addr;
int ffs, rm, i;
ffs = plen / 8;
rm = plen % 8;
if (rm != 0) {
rm = 8 - rm;
rm = 0xFFu << rm;
}
for (i = 0; i < ffs; i++)
mask[i] = 0xFFu;
if (rm != 0) {
mask[i] = rm;
i++;
}
for (; i < sizeofaddr; i++)
mask[i] = 0;
}
/* **************************************************** *
* calculate the length of netmask prefix *
* **************************************************** */
int
ni_prefix(void * ap, int sz)
{
unsigned char byte, * addr = (unsigned char *)ap;
int bit, bp, plen = 0;
for (bp = 0; bp < sz; bp++) {
if (addr[bp] != 0xFFu)
break;
plen += 8;
}
if (bp == sz)
return plen;
byte = addr[bp];
for (bit = 0x80u; bit != 0; bit >>= 1) { /* for (bit = 7; bit != 0; bit--, plen++) */
if (byte & bit) { /* if (!(name[byte] & (1 << bit))) */
byte ^= bit; /* break; */
plen++;
}
else if (byte != 0) /* for (; bit != 0; bit--) */
return 0; /* if (name[byte] & (1 << bit)) */
else /* return 0; */
break;
}
bp++;
for (; bp < sz; bp++) {
if (addr[bp] != 0)
return 0;
}
return plen;
}
/* **************************************************** *
* constructor registration *
* **************************************************** */
/* for ifreq or equivalent flavor support */
struct ni_ifconf_flavor * nifcf = NULL;
void
ni_ifcf_register(struct ni_ifconf_flavor * nifp)
{
nifp->ni_ifcf_next = nifcf;
nifcf = nifp;
}
struct ni_ifconf_flavor *
ni_ifcf_get(enum ni_FLAVOR type)
{
struct ni_ifconf_flavor * nifp;
for (nifp = nifcf; nifp != NULL; nifp = nifp->ni_ifcf_next)
if (nifp->ni_type == type)
return nifp;
errno = ENOSYS;
return NULL;
}
struct ni_ifconf_flavor *
ni_safe_ifcf_get(enum ni_FLAVOR type)
{
struct ni_ifconf_flavor * nifp;
if ((nifp = ni_ifcf_get(type)) != NULL)
return nifp;
return ni_ifcf_get(NI_IFREQ);
}
/* **************************************************** *
* developer support, not for production *
* **************************************************** */
int
ni_developer(enum ni_FLAVOR type)
{
void * notused = NULL;
struct ni_ifconf_flavor * nifp = ni_ifcf_get(type);
if (nifp == NULL)
return ENOSYS;
return nifp->developer(notused);
}
/* **************************************************** *
* IPV6 support for linux like type info *
* **************************************************** */
/* does not have to be ifdef'd #ifdef LOCAL_SIZEOF_SOCKADDR_IN6 */
/* scope flags rfc-2373
*
0 reserved
1 node-local
2 link-local
3 unassigned
4 unassigned
5 site-local
6 unassigned
7 unassigned
8 organization-local
9 unassigned
A unassigned
B unassigned
C unassigned
D unassigned
E global scope
F reserved
*/
# ifdef ___NEVER_DEFINED___for_info
/* 0x0000 0xe
#define IPV6_ADDR_LOOPBACK 0x0010u /* 0x1 aka NODELOCAL, INTERFACELOCAL */
#define IPV6_ADDR_LINKLOCAL 0x0020u /* 0x2 */
#define IPV6_ADDR_SITELOCAL 0x0040u /* 0x5 */
#define IPV6_ADDR_COMPATv4 0x0080u /* 0x10 mapped back out of range */
# endif
int
ni_lx_type2scope(int lscope)
{
lscope &= 0xF0u;
switch (lscope) {
case 0 :
return 0xEu;
case 0x10 :
return 0x1;
case 0x20 :
return 0x2;
case 0x40 :
return 0x5;
case 0x80:
return 0x10; /* linux compat-v4 */
}
return 0;
}
const ni_iff_t ni_lx_type2txt[] = {
{ IPV6_ADDR_ANY, "addr-any" },
{ IPV6_ADDR_UNICAST, "unicast" },
{ IPV6_ADDR_MULTICAST, "multicast" },
{ IPV6_ADDR_ANYCAST, "anycast" },
{ IPV6_ADDR_LOOPBACK, "loopback" },
{ IPV6_ADDR_LINKLOCAL, "link-local" },
{ IPV6_ADDR_SITELOCAL, "site-local" },
{ IPV6_ADDR_COMPATv4, "compat-v4" },
{ IPV6_ADDR_SCOPE_MASK, "scope-mask" },
{ IPV6_ADDR_MAPPED, "mapped" },
{ IPV6_ADDR_RESERVED, "reserved" },
{ IPV6_ADDR_ULUA, "uniq-lcl-unicast" },
{ IPV6_ADDR_6TO4, "6to4" },
{ IPV6_ADDR_6BONE, "6bone" },
{ IPV6_ADDR_AGU, "global-unicast" },
{ IPV6_ADDR_UNSPECIFIED, "unspecified" },
{ IPV6_ADDR_SOLICITED_NODE, "solicited-node" },
{ IPV6_ADDR_ISATAP, "ISATAP" },
{ IPV6_ADDR_PRODUCTIVE, "productive" },
{ IPV6_ADDR_6TO4_MICROSOFT, "6to4-ms" },
{ IPV6_ADDR_TEREDO, "teredo" },
{ IPV6_ADDR_ORCHID, "orchid" },
{ IPV6_ADDR_NON_ROUTE_DOC, "non-routeable-doc" }
};
int
ni_sizeof_type2txt()
{
return sizeof(ni_lx_type2txt);
}
void
ni_linux_scope2txt(uint32_t flags)
{
int i, n = sizeof(ni_lx_type2txt) / sizeof(ni_iff_t);
for (i=0; i < n; i++)
if (flags & ni_lx_type2txt[i].iff_val)
printf("%s ",ni_lx_type2txt[i].iff_nam);
}
/* does not have to be ifdef'd #endif LOCAL_SIZEOF_SOCKADDR_IN6 */