Changeset 43214 in vbox for trunk/src/VBox/Runtime/common
- Timestamp:
- Sep 6, 2012 9:16:55 AM (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/common/string/RTStrIPv6.cpp
r43175 r43214 36 36 #include "internal/iprt.h" 37 37 #include "internal/string.h" 38 39 40 /** @page pg_rtnetipv6_addr IPv6 Address Format 41 * 42 * IPv6 Addresses, their representation in text and other problems. 43 * 44 * The following is based on: 45 * 46 * - http://tools.ietf.org/html/rfc4291 47 * - http://tools.ietf.org/html/rfc5952 48 * - http://tools.ietf.org/html/rfc6052 49 * 50 * 51 * Before you start using those functions, you should have an idea of 52 * what you're dealing with, before you come and blame the functions... 53 * 54 * First of all, the address itself: 55 * 56 * An address is written like this: (READ THIS FINE MANUAL!) 57 * 58 * - 2001:db8:abc:def::1 59 * 60 * The characters between two colons are called a "hextet". 61 * Each hextet consists of four characters and each IPv6 address 62 * consists of a maximum of eight hextets. So a full blown address 63 * would look like this: 64 * 65 * - 1111:2222:3333:4444:5555:6666:7777:8888 66 * 67 * The allowed characters are "0123456789abcdef". They have to be 68 * lower case. Upper case is not allowed. 69 * 70 * *** Gaps and adress shortening 71 * 72 * If an address contains hextets that contain only "0"s, they 73 * can be shortened, like this: 74 * 75 * - 1111:2222:0000:0000:0000:0000:7777:8888 -> 1111:2222::7777:8888 76 * 77 * The double colon represents the hextets that have been shortened "::". 78 * The "::" will be called "gap" from now on. 79 * 80 * When shortening an address, there are some special rules that need to be applied: 81 * 82 * - Shorten always the longest group of hextets. 83 * 84 * Let's say, you have this address: 2001:db8:0:0:0:1:0:0 then it has to be 85 * shortened to "2001:db8::1:0:0". Shortening to "2001:db8:0:0:0:1::" would 86 * return an error. 87 * 88 * - Two or more gaps the same size. 89 * 90 * Let's say you have this address: 2001:db8:0:0:1:0:0:1. As you can see, there 91 * are two gaps, both the size of two hextets. If you shorten the last two hextets, 92 * you end up in pain, as the RFC forbids this, so the correct address is: 93 * "2001:db8::1:0:0:1" 94 * 95 * It's important to note that an address can only be shortened ONE TIME! 96 * This is invalid: "2001:db8::1::1" 97 * 98 * *** The scope. 99 * 100 * Each address has a so called "scope" it is added to the end of the address, 101 * separated by a percent sign "%". If there is no scope at the end, it defaults 102 * to "0". 103 * 104 * So "2001:db8::1" is the same as "2001:db8::1%0". 105 * 106 * As in IPv6 all network interfaces can/should have the same address, the scope 107 * gives you the ability to choose on which interface the system should listen. 108 * 109 * AFAIK, the scope can be used with unicast as well as link local addresses, but 110 * it is mandatory with link local addresses (starting with fe80::). 111 * 112 * On Linux the default scope is the interface's name. On Windows it's just the index 113 * of the interface. Run "route print -6" in the shell, to see the interface's index 114 * on Winodows. 115 * 116 * All functions can deal with the scope, and DO NOT warn if you put garbage there. 117 * 118 * *** Port added to the IPv6 address 119 * 120 * There is only one way to add a port to an IPv6 address is to embed it in brackets: 121 * 122 * [2001:db8::1]:12345 123 * 124 * This gives you the address "2001:db8::1" and the port "12345". 125 * 126 * What also works, but is not recommended by rfc is to separate the port 127 * by a dot: 128 * 129 * 2001:db8::1.12345 130 * 131 * It even works with embedded IPv4 addresses. 132 * 133 * *** Special addresses and how they are written 134 * 135 * The following are notations to represent "special addresses". 136 * 137 * "::" IN6ADDR_ANY 138 * ":::123" IN6ADDR_ANY with port "123" 139 * "[::]:123" IN6ADDR_ANY with port "123" 140 * "[:::123]" -> NO. Not allowed and makes no sense 141 * "::1" -> address of the loopback device (127.0.0.1 in v4) 142 * 143 * On systems with dual sockets, one can use so called embedded IPv4 addresses: 144 * 145 * "::ffff:192.168.1.1" results in the IPv6 address "::ffff:c0a8:0101" as two octets 146 * of the IPv4 address will be converted to one hextet in the IPv6 address. 147 * 148 * The prefix of such addresses MUST BE "::ffff:", 10 bytes as zero and two bytes as 255. 149 * 150 * The so called IPv4-compatible IPv6 addresses are deprecated and no longer in use. 151 * 152 * *** Valid addresses and string 153 * 154 * If you use any of the IPv6 address functions, keep in mind, that those addresses 155 * are all returning "valid" even if the underlying system (e.g. VNC) doesn't like 156 * such strings. 157 * 158 * [2001:db8::1] 159 * [2001:db8::1]:12345 160 * 161 * and so on. So to make sure you only pass the underlying software a pure IPv6 address 162 * without any garbage, you should use the "outAddress" parameters to get a RFC compliant 163 * address returned. 164 * 165 * So after reading the above, you'll start using the functions and see a bool called 166 * "followRfc" which is true by default. This is what this bool does: 167 * 168 * The following addresses all represent the exact same address: 169 * 170 * 1 - 2001:db8::1 171 * 2 - 2001:db8:0::1 172 * 3 - 2001:0db8:0000:0000:0000:0000:0000:0001 173 * 4 - 2001:DB8::1 174 * 5 - [2001:db8::1] 175 * 6 - [2001:db8:0::1] 176 * 177 * According to RFC 5952, number two, three, four and six are invalid. 178 * 179 * #2 - because there is a single hextet that hasn't been shortened 180 * 181 * #3 - because there has nothing been shortened (hextets 3 to 7) and 182 * there are leading zeros in at least one hextet ("0db8") 183 * 184 * #4 - all characters in an IPv6 address have to be lower case 185 * 186 * #6 - same as two but included in brackets 187 * 188 * If you follow RFC, the above addresses are not converted and an 189 * error is returned. If you turn RFC off, you will get the expected 190 * representation of the address. 191 * 192 * It's a nice way to convert "weird" addresses to rfc compliant addresses 193 * 194 */ 195 38 196 39 197 /** … … 972 1130 } 973 1131 974 RTDECL(int) RTStrIsIpAddr6(const char *psz, char *pszResultAddress, size_t resultAddressSize, bool addressOnly, bool followRfc) 1132 1133 /** 1134 * Tests if the given string is a valid IPv6 address. 1135 * 1136 * @returns 0 if valid, some random number if not. THIS IS NOT AN IPRT STATUS! 1137 * @param psz The string to test 1138 * @param pszResultAddress plain address, optional read "valid addresses 1139 * and strings" above. 1140 * @param resultAddressSize size of pszResultAddress 1141 * @param addressOnly return only the plain address (no scope) 1142 * Ignored, and will always return the if id 1143 */ 1144 static int rtNetIpv6CheckAddrStr(const char *psz, char *pszResultAddress, size_t resultAddressSize, bool addressOnly, bool followRfc) 975 1145 { 976 1146 int rc; … … 1045 1215 1046 1216 } 1047 RT_EXPORT_SYMBOL(RTStrIsIpAddr6); 1048 1049 1050 RTDECL(int) RTStrIsIpAddr4(const char *psz) 1217 1218 1219 RTDECL(bool) RTNetIsIPv6AddrStr(const char *pszAddress) 1051 1220 { 1052 const char szIpV4Digits[] = "0123456789."; 1053 char *pStart = NULL, *pEnd = NULL, *pFrom = NULL, *pTo = NULL, *pNow = NULL, *pDigit = NULL; 1054 char *pChar = NULL, *pNext = NULL; 1055 1056 uint32_t ulDots = 0; 1057 uint32_t ulOctet = 0; 1058 int rc = VINF_SUCCESS; 1059 1060 char szDummy[4]; 1061 1062 if (strlen(psz) < 7 || strlen(psz) > 15) 1063 return -1; 1064 1065 pStart = pNow = pFrom = pTo = pEnd = (char *)psz; 1066 1221 return rtNetIpv6CheckAddrStr(pszAddress, NULL, 0, true, true); 1222 } 1223 RT_EXPORT_SYMBOL(RTNetIsIPv6AddrStr); 1224 1225 1226 RTDECL(bool) RTNetIsIPv4AddrStr(const char *pszAddress) 1227 { 1228 static char const s_szIpV4Digits[] = "0123456789."; 1229 1230 size_t cchAddress = strlen(pszAddress); 1231 if (cchAddress < 7 || cchAddress > 15) 1232 return false; 1233 1234 const char *pStart, *pFrom, *pTo, *pNow; 1235 pStart = pNow = pFrom = pTo = pszAddress; 1236 1237 unsigned cOctets = 0; 1067 1238 while (*pNow != '\0') 1068 1239 { 1069 pChar = NULL; 1070 pDigit = NULL; 1071 pNext = NULL; 1072 1073 pChar = (char *)memchr(szIpV4Digits, *pNow, strlen(szIpV4Digits)); 1074 pDigit = (char *)memchr(szIpV4Digits, *pNow, strlen(szIpV4Digits) - 1); 1075 pNext = pNow + 1; 1240 const char *pChar = (const char *)memchr(s_szIpV4Digits, *pNow, sizeof(s_szIpV4Digits) - 1); 1241 const char *pDigit = (const char *)memchr(s_szIpV4Digits, *pNow, sizeof(s_szIpV4Digits) - 2); 1242 const char *pNext = pNow + 1; 1076 1243 1077 1244 if (!pChar) 1078 return -2;1245 return false; 1079 1246 1080 1247 if (pDigit && *pNext != '\0') … … 1090 1257 pTo = pNow; 1091 1258 1092 if ((pTo - pFrom) > 2) 1093 return -3; 1094 1095 memset(szDummy, '\0', 4); 1096 memcpy(szDummy, pFrom, (pTo - pFrom) + 1); 1097 1098 rc = RTStrToUInt32Ex(szDummy, NULL, 10, &ulOctet); 1099 1100 if (!RT_SUCCESS(rc)) 1101 return -6; 1102 1103 if (ulOctet > 255) 1104 return -4; 1105 1106 ulDots++; 1259 size_t cchSub = pTo - pFrom; 1260 if (cchSub > 2) 1261 return false; 1262 1263 char szDummy[4] = { 0, 0, 0, 0 }; 1264 memcpy(szDummy, pFrom, cchSub + 1); 1265 1266 int rc = RTStrToUInt8Ex(szDummy, NULL, 10, NULL); 1267 if (rc != VINF_SUCCESS) 1268 return false; 1269 1270 cOctets++; 1271 if (cOctets > 4) 1272 return false; 1107 1273 pFrom = pNext; 1108 1274 } … … 1110 1276 } 1111 1277 1112 if ( ulDots != 4) // yes, it's four1113 return -5;1114 1115 return 0;1278 if (cOctets != 4) 1279 return false; 1280 1281 return true; 1116 1282 } 1117 RT_EXPORT_SYMBOL(RT StrIsIpAddr4);1118 1283 RT_EXPORT_SYMBOL(RTNetIsIPv4AddrStr); 1284
Note:
See TracChangeset
for help on using the changeset viewer.