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