/* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * Common (shared) routines used by in.routed daemon and the * the rtquery utility program */ #include "defs.h" #include /* Return the classical netmask for an IP address. */ in_addr_t /* host byte order */ std_mask(in_addr_t addr) /* network byte order */ { addr = ntohl(addr); if (addr == 0) /* default route has mask 0 */ return (0); if (IN_CLASSA(addr)) return (IN_CLASSA_NET); if (IN_CLASSB(addr)) return (IN_CLASSB_NET); if (IN_CLASSC(addr)) return (IN_CLASSC_NET); return (IN_CLASSE_NET); } /* * Get a network number as a name or a number, with an optional "/xx" * netmask. */ boolean_t /* 0=bad */ getnet(const char *name, in_addr_t *netp, /* network in host byte order */ in_addr_t *maskp) /* masks are always in host order */ { int i; struct netent *np; in_addr_t mask; /* in host byte order */ struct in_addr in; /* a network and so host byte order */ char hname[MAXHOSTNAMELEN+1]; char *mname, *p; /* * The "name" argument of this function can be one of * the follwoing: * a) network name/mask * b) network name * c) network number/mask * d) network number * e) host IP address/mask * f) host IP address * g) "default" * * Detect and separate "1.2.3.4/24" */ if (NULL != (mname = strrchr(name, '/'))) { i = (int)(mname - name); if (i > (int)sizeof (hname)-1) /* name too long */ return (_B_FALSE); (void) memmove(hname, name, i); hname[i] = '\0'; mname++; name = hname; } if ((in.s_addr = inet_network(name)) == (in_addr_t)-1) { if (mname == NULL && strcasecmp(name, "default") == 0) in.s_addr = ntohl(RIP_DEFAULT); else if ((np = getnetbyname(name)) != NULL) in.s_addr = np->n_net; else return (_B_FALSE); } /* Left-align the host-byte-order result from above. */ if (0 == (in.s_addr & 0xff000000)) in.s_addr <<= 8; if (0 == (in.s_addr & 0xff000000)) in.s_addr <<= 8; if (0 == (in.s_addr & 0xff000000)) in.s_addr <<= 8; if (mname == NULL) { mask = std_mask(htonl(in.s_addr)); if ((~mask & in.s_addr) != 0) mask = HOST_MASK; } else { mask = (uint32_t)strtoul(mname, &p, 0); if (*p != '\0' || mask > 32 || mname == p) return (_B_FALSE); if (mask != 0) mask = HOST_MASK << (32-mask); } /* must have mask of 0 with default */ if (mask != 0 && in.s_addr == RIP_DEFAULT) return (_B_FALSE); /* no host bits allowed in a network number */ if ((~mask & in.s_addr) != 0) return (_B_FALSE); /* require non-zero network number */ if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT) return (_B_FALSE); if ((in.s_addr >> 24) == 0 && in.s_addr != RIP_DEFAULT) return (_B_FALSE); if ((in.s_addr >> 24) == 0xff) return (_B_FALSE); *netp = in.s_addr; *maskp = mask; return (_B_TRUE); } /* * Convert string to printable characters */ char * qstring(const uchar_t *srcp, int len) { /* * Authentication schemes for RIPv2 uses the space of an * 20-octet route entry. */ static char buf[8*20+1]; char *prcp, *tmp_ptr; uchar_t c; const uchar_t *s2; s2 = srcp + len; while (s2 > srcp && *--s2 == '\0') len--; for (prcp = buf; len != 0 && prcp < &buf[sizeof (buf)-1]; len--) { c = *srcp++; if (isprint(c) && c != '\\') { *prcp++ = c; continue; } *prcp++ = '\\'; tmp_ptr = strchr("\\\\\nn\rr\tt\bb\aa\ff", c); if (tmp_ptr != NULL) *prcp++ = tmp_ptr[1]; else prcp += snprintf(prcp, (sizeof (buf) - (strlen(buf)+1)), "%o", c); } *prcp = '\0'; return (buf); } /* like strtok(), but honoring backslash and not changing the source string */ int /* 0=ok, -1=bad */ parse_quote(char **linep, /* look here */ const char *delims, /* for these delimiters */ char *delimp, /* 0 or put found delimiter here */ char *buf, /* copy token to here */ int lim) /* at most this many bytes */ { char c = '\0', *pc; const char *p; pc = *linep; if (*pc == '\0') return (-1); while (lim != 0) { c = *pc++; if (c == '\0') break; if (c == '\\' && *pc != '\0') { c = *pc++; switch (c) { case 'n': c = '\n'; break; case 'r': c = '\r'; break; case 't': c = '\t'; break; case 'b': c = '\b'; } if (c >= '0' && c <= '7') { c -= '0'; if (*pc >= '0' && *pc <= '7') { c = (c<<3)+(*pc++ - '0'); if (*pc >= '0' && *pc <= '7') c = (c<<3)+(*pc++ - '0'); } } } else { for (p = delims; *p != '\0'; ++p) { if (*p == c || isspace(c) && *p == ' ') goto exit; } } *buf++ = c; --lim; } exit: if (lim == 0) return (-1); *buf = '\0'; /* terminate copy of token */ if (delimp != NULL) *delimp = c; /* return delimiter */ *linep = pc-1; /* say where we ended */ return (0); } /* * Find the option buffer in the msg corresponding to cmsg_type. */ void * find_ancillary(struct msghdr *msg, int cmsg_type) { struct cmsghdr *cmsg; for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == cmsg_type) { return (CMSG_DATA(cmsg)); } } return (NULL); }