Changeset 50456 in vbox for trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp
- Timestamp:
- Feb 14, 2014 2:10:23 AM (11 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/net/netaddrstr2.cpp
r50418 r50456 31 31 #include <iprt/net.h> 32 32 33 #include <iprt/asm.h> 33 34 #include <iprt/mem.h> 34 35 #include <iprt/string.h> … … 123 124 } 124 125 RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr); 126 127 128 static int rtNetStrToHexGroup(const char *pcszValue, char **ppszNext, 129 uint16_t *pu16) 130 { 131 char *pszNext; 132 int rc; 133 134 rc = RTStrToUInt16Ex(pcszValue, &pszNext, 16, pu16); 135 if (RT_FAILURE(rc)) 136 return rc; 137 138 if ( rc != VINF_SUCCESS 139 && rc != VWRN_TRAILING_CHARS 140 && rc != VWRN_TRAILING_SPACES) 141 { 142 return -rc; /* convert warning to error */ 143 } 144 145 /* parser always accepts 0x prefix */ 146 if (pcszValue[0] == '0' && (pcszValue[1] == 'x' || pcszValue[1] == 'X')) 147 { 148 if (pu16) 149 *pu16 = 0; 150 if (ppszNext) 151 *ppszNext = (/* UNCONST */ char *)pcszValue + 1; /* to 'x' */ 152 return VWRN_TRAILING_CHARS; 153 } 154 155 /* parser accepts leading zeroes "000000f" */ 156 if (pszNext - pcszValue > 4) 157 return VERR_PARSE_ERROR; 158 159 if (ppszNext) 160 *ppszNext = pszNext; 161 return rc; 162 } 163 164 165 /* 166 * This function deals only with the hex-group IPv6 address syntax 167 * proper (with possible embedded IPv4). 168 */ 169 DECLHIDDEN(int) rtNetStrToIPv6AddrBase(const char *pcszAddr, PRTNETADDRIPV6 pAddrResult, 170 char **ppszNext) 171 { 172 RTNETADDRIPV6 ipv6; 173 RTNETADDRIPV4 ipv4; 174 const char *pcszPos; 175 char *pszNext; 176 int iGroup; 177 uint16_t u16; 178 int rc; 179 180 memset(&ipv6, 0, sizeof(ipv6)); 181 182 pcszPos = pcszAddr; 183 184 if (pcszPos[0] == ':') /* compressed zero run at the beginning? */ 185 { 186 if (pcszPos[1] != ':') 187 return VERR_PARSE_ERROR; 188 189 pcszPos += 2; /* skip over "::" */ 190 pszNext = (/* UNCONST */ char *)pcszPos; 191 iGroup = 1; 192 } 193 else 194 { 195 /* 196 * Scan forward until we either get complete address or find 197 * "::" compressed zero run. 198 */ 199 for (iGroup = 0; iGroup < 8; ++iGroup) 200 { 201 /* check for embedded IPv4 at the end */ 202 if (iGroup == 6) 203 { 204 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext); 205 if (rc == VINF_SUCCESS) 206 { 207 ipv6.au32[3] = ipv4.au32[0]; 208 iGroup = 8; /* filled 6 and 7 */ 209 break; /* we are done */ 210 } 211 } 212 213 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16); 214 if (RT_FAILURE(rc)) 215 return VERR_PARSE_ERROR; 216 217 ipv6.au16[iGroup] = RT_H2N_U16(u16); 218 219 if (iGroup == 7) 220 pcszPos = pszNext; 221 else 222 { 223 /* skip the colon that delimits this group */ 224 if (*pszNext != ':') 225 return VERR_PARSE_ERROR; 226 pcszPos = pszNext + 1; 227 228 /* compressed zero run? */ 229 if (*pcszPos == ':') 230 { 231 ++pcszPos; /* skip over :: */ 232 pszNext += 2; /* skip over :: (in case we are done) */ 233 iGroup += 2; /* current field and the zero in the next */ 234 break; 235 } 236 } 237 } 238 } 239 240 if (iGroup != 8) 241 { 242 /* 243 * iGroup is the first group that can be filled by the part of 244 * the address after "::". 245 */ 246 RTNETADDRIPV6 ipv6Tail; 247 const int iMaybeStart = iGroup; 248 int j; 249 250 memset(&ipv6Tail, 0, sizeof(ipv6Tail)); 251 252 /* 253 * We try to accept longest match; we'll shift if necessary. 254 * Unlike the first loop, a failure to parse a group doesn't 255 * mean invalid address. 256 */ 257 for (; iGroup < 8; ++iGroup) 258 { 259 /* check for embedded IPv4 at the end */ 260 if (iGroup <= 6) 261 { 262 rc = rtNetStrToIPv4AddrEx(pcszPos, &ipv4, &pszNext); 263 if (rc == VINF_SUCCESS) 264 { 265 ipv6Tail.au16[iGroup] = ipv4.au16[0]; 266 ipv6Tail.au16[iGroup + 1] = ipv4.au16[1]; 267 iGroup = iGroup + 2; /* these two are done */ 268 break; /* the rest is trailer */ 269 } 270 } 271 272 rc = rtNetStrToHexGroup(pcszPos, &pszNext, &u16); 273 if (RT_FAILURE(rc)) 274 break; 275 276 ipv6Tail.au16[iGroup] = RT_H2N_U16(u16); 277 278 if (iGroup == 7) 279 pcszPos = pszNext; 280 else 281 { 282 if (*pszNext != ':') 283 { 284 ++iGroup; /* this one is done */ 285 break; /* the rest is trailer */ 286 } 287 288 pcszPos = pszNext + 1; 289 } 290 } 291 292 for (j = 7, --iGroup; iGroup >= iMaybeStart; --j, --iGroup) 293 ipv6.au16[j] = ipv6Tail.au16[iGroup]; 294 } 295 296 if (pAddrResult != NULL) 297 memcpy(pAddrResult, &ipv6, sizeof(ipv6)); 298 if (ppszNext != NULL) 299 *ppszNext = pszNext; 300 return VINF_SUCCESS; 301 } 302 303 304 DECLHIDDEN(int) rtNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr, 305 char **ppszZone, char **ppszNext) 306 { 307 char *pszNext, *pszZone; 308 int rc; 309 310 rc = rtNetStrToIPv6AddrBase(pcszAddr, pAddr, &pszNext); 311 if (RT_FAILURE(rc)) 312 return rc; 313 314 if (*pszNext != '%') /* is there a zone id? */ 315 { 316 pszZone = NULL; 317 } 318 else 319 { 320 pszZone = pszNext + 1; /* skip '%' zone id delimiter */ 321 if (*pszZone == '\0') 322 return VERR_PARSE_ERROR; /* empty zone id */ 323 324 /* 325 * XXX: this is speculative as zone id syntax is 326 * implementation dependent, so we kinda guess here (accepting 327 * unreserved characters from URI syntax). 328 */ 329 for (pszNext = pszZone; *pszNext != '\0'; ++pszNext) 330 { 331 const char c = *pszNext; 332 if ( !('0' <= c && c <= '9') 333 && !('a' <= c && c <= 'z') 334 && !('A' <= c && c <= 'Z') 335 && c != '_' 336 && c != '.' 337 && c != '-' 338 && c != '~') 339 { 340 break; 341 } 342 } 343 } 344 345 if (ppszZone != NULL) 346 *ppszZone = pszZone; 347 if (ppszNext != NULL) 348 *ppszNext = pszNext; 349 350 if (*pszNext == '\0') /* all input string consumed */ 351 return VINF_SUCCESS; 352 else 353 { 354 while (*pszNext == ' ' || *pszNext == '\t') 355 ++pszNext; 356 if (*pszNext == '\0') 357 return VWRN_TRAILING_SPACES; 358 else 359 return VWRN_TRAILING_CHARS; 360 } 361 } 362 363 364 RTDECL(int) RTNetStrToIPv6AddrEx(const char *pcszAddr, PRTNETADDRIPV6 pAddr, 365 char **ppszNext) 366 { 367 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER); 368 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER); 369 370 return rtNetStrToIPv6AddrBase(pcszAddr, pAddr, ppszNext); 371 } 372 RT_EXPORT_SYMBOL(RTNetStrToIPv6AddrEx); 373 374 375 RTDECL(int) RTNetStrToIPv6Addr(const char *pcszAddr, PRTNETADDRIPV6 pAddr, 376 char **ppszZone) 377 { 378 int rc; 379 380 AssertPtrReturn(pcszAddr, VERR_INVALID_PARAMETER); 381 AssertPtrReturn(pAddr, VERR_INVALID_PARAMETER); 382 AssertPtrReturn(ppszZone, VERR_INVALID_PARAMETER); 383 384 pcszAddr = RTStrStripL(pcszAddr); 385 rc = rtNetStrToIPv6AddrEx(pcszAddr, pAddr, ppszZone, NULL); 386 if (rc != VINF_SUCCESS && rc != VWRN_TRAILING_SPACES) 387 return VERR_INVALID_PARAMETER; 388 389 return VINF_SUCCESS; 390 } 391 RT_EXPORT_SYMBOL(RTNetStrToIPv6Addr); 392 393 394 RTDECL(bool) RTNetIsIPv6AddrStr(const char *pcszAddr) 395 { 396 RTNETADDRIPV6 addrIPv6; 397 int rc; 398 399 if (pcszAddr == NULL) 400 return false; 401 402 rc = rtNetStrToIPv6AddrEx(pcszAddr, &addrIPv6, NULL, NULL); 403 if (rc != VINF_SUCCESS) 404 return false; 405 406 return true; 407 } 408 RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr);
Note:
See TracChangeset
for help on using the changeset viewer.