1 /* 2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 #pragma ident "%Z%%M% %I% %E% SMI" 7 8 /* 9 * Common (shared) routines used by in.routed daemon and the 10 * the rtquery utility program 11 */ 12 13 #include "defs.h" 14 #include <ctype.h> 15 16 /* Return the classical netmask for an IP address. */ 17 in_addr_t /* host byte order */ 18 std_mask(in_addr_t addr) /* network byte order */ 19 { 20 addr = ntohl(addr); 21 22 if (addr == 0) /* default route has mask 0 */ 23 return (0); 24 if (IN_CLASSA(addr)) 25 return (IN_CLASSA_NET); 26 if (IN_CLASSB(addr)) 27 return (IN_CLASSB_NET); 28 if (IN_CLASSC(addr)) 29 return (IN_CLASSC_NET); 30 return (IN_CLASSE_NET); 31 } 32 33 /* 34 * Get a network number as a name or a number, with an optional "/xx" 35 * netmask. 36 */ 37 boolean_t /* 0=bad */ 38 getnet(const char *name, 39 in_addr_t *netp, /* network in host byte order */ 40 in_addr_t *maskp) /* masks are always in host order */ 41 { 42 int i; 43 struct netent *np; 44 in_addr_t mask; /* in host byte order */ 45 struct in_addr in; /* a network and so host byte order */ 46 char hname[MAXHOSTNAMELEN+1]; 47 char *mname, *p; 48 49 50 /* 51 * The "name" argument of this function can be one of 52 * the follwoing: 53 * a) network name/mask 54 * b) network name 55 * c) network number/mask 56 * d) network number 57 * e) host IP address/mask 58 * f) host IP address 59 * g) "default" 60 * 61 * Detect and separate "1.2.3.4/24" 62 */ 63 if (NULL != (mname = strrchr(name, '/'))) { 64 i = (int)(mname - name); 65 if (i > (int)sizeof (hname)-1) /* name too long */ 66 return (_B_FALSE); 67 (void) memmove(hname, name, i); 68 hname[i] = '\0'; 69 mname++; 70 name = hname; 71 } 72 73 if ((in.s_addr = inet_network(name)) == (in_addr_t)-1) { 74 if (mname == NULL && strcasecmp(name, "default") == 0) 75 in.s_addr = ntohl(RIP_DEFAULT); 76 else if ((np = getnetbyname(name)) != NULL) 77 in.s_addr = np->n_net; 78 else 79 return (_B_FALSE); 80 } 81 /* Left-align the host-byte-order result from above. */ 82 if (0 == (in.s_addr & 0xff000000)) 83 in.s_addr <<= 8; 84 if (0 == (in.s_addr & 0xff000000)) 85 in.s_addr <<= 8; 86 if (0 == (in.s_addr & 0xff000000)) 87 in.s_addr <<= 8; 88 89 if (mname == NULL) { 90 mask = std_mask(htonl(in.s_addr)); 91 if ((~mask & in.s_addr) != 0) 92 mask = HOST_MASK; 93 } else { 94 mask = (uint32_t)strtoul(mname, &p, 0); 95 if (*p != '\0' || mask > 32 || mname == p) 96 return (_B_FALSE); 97 if (mask != 0) 98 mask = HOST_MASK << (32-mask); 99 } 100 101 /* must have mask of 0 with default */ 102 if (mask != 0 && in.s_addr == RIP_DEFAULT) 103 return (_B_FALSE); 104 /* no host bits allowed in a network number */ 105 if ((~mask & in.s_addr) != 0) 106 return (_B_FALSE); 107 /* require non-zero network number */ 108 if ((mask & in.s_addr) == 0 && in.s_addr != RIP_DEFAULT) 109 return (_B_FALSE); 110 if ((in.s_addr >> 24) == 0 && in.s_addr != RIP_DEFAULT) 111 return (_B_FALSE); 112 if ((in.s_addr >> 24) == 0xff) 113 return (_B_FALSE); 114 115 *netp = in.s_addr; 116 *maskp = mask; 117 return (_B_TRUE); 118 } 119 120 /* 121 * Convert string to printable characters 122 */ 123 char * 124 qstring(const uchar_t *srcp, int len) 125 { 126 /* 127 * Authentication schemes for RIPv2 uses the space of an 128 * 20-octet route entry. 129 */ 130 static char buf[8*20+1]; 131 char *prcp, *tmp_ptr; 132 uchar_t c; 133 const uchar_t *s2; 134 135 s2 = srcp + len; 136 while (s2 > srcp && *--s2 == '\0') 137 len--; 138 for (prcp = buf; len != 0 && prcp < &buf[sizeof (buf)-1]; len--) { 139 c = *srcp++; 140 if (isprint(c) && c != '\\') { 141 *prcp++ = c; 142 continue; 143 } 144 145 *prcp++ = '\\'; 146 tmp_ptr = strchr("\\\\\nn\rr\tt\bb\aa\ff", c); 147 if (tmp_ptr != NULL) 148 *prcp++ = tmp_ptr[1]; 149 else 150 prcp += snprintf(prcp, 151 (sizeof (buf) - (strlen(buf)+1)), "%o", c); 152 } 153 *prcp = '\0'; 154 return (buf); 155 } 156 157 /* like strtok(), but honoring backslash and not changing the source string */ 158 int /* 0=ok, -1=bad */ 159 parse_quote(char **linep, /* look here */ 160 const char *delims, /* for these delimiters */ 161 char *delimp, /* 0 or put found delimiter here */ 162 char *buf, /* copy token to here */ 163 int lim) /* at most this many bytes */ 164 { 165 char c = '\0', *pc; 166 const char *p; 167 168 169 pc = *linep; 170 if (*pc == '\0') 171 return (-1); 172 173 while (lim != 0) { 174 c = *pc++; 175 if (c == '\0') 176 break; 177 178 if (c == '\\' && *pc != '\0') { 179 c = *pc++; 180 switch (c) { 181 case 'n': 182 c = '\n'; 183 break; 184 case 'r': 185 c = '\r'; 186 break; 187 case 't': 188 c = '\t'; 189 break; 190 case 'b': 191 c = '\b'; 192 } 193 if (c >= '0' && c <= '7') { 194 c -= '0'; 195 if (*pc >= '0' && *pc <= '7') { 196 c = (c<<3)+(*pc++ - '0'); 197 if (*pc >= '0' && *pc <= '7') 198 c = (c<<3)+(*pc++ - '0'); 199 } 200 } 201 202 } else { 203 for (p = delims; *p != '\0'; ++p) { 204 if (*p == c || isspace(c) && *p == ' ') 205 goto exit; 206 } 207 } 208 209 *buf++ = c; 210 --lim; 211 } 212 exit: 213 if (lim == 0) 214 return (-1); 215 216 *buf = '\0'; /* terminate copy of token */ 217 if (delimp != NULL) 218 *delimp = c; /* return delimiter */ 219 *linep = pc-1; /* say where we ended */ 220 return (0); 221 } 222 223 /* 224 * Find the option buffer in the msg corresponding to cmsg_type. 225 */ 226 void * 227 find_ancillary(struct msghdr *msg, int cmsg_type) 228 { 229 struct cmsghdr *cmsg; 230 231 for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; 232 cmsg = CMSG_NXTHDR(msg, cmsg)) { 233 if (cmsg->cmsg_level == IPPROTO_IP && 234 cmsg->cmsg_type == cmsg_type) { 235 return (CMSG_DATA(cmsg)); 236 } 237 } 238 return (NULL); 239 } 240