1 | /* Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. |
2 | Copyright (c) 2014 MariaDB Foundation |
3 | |
4 | This program is free software; you can redistribute it and/or modify |
5 | it under the terms of the GNU General Public License as published by |
6 | the Free Software Foundation; version 2 of the License. |
7 | |
8 | This program is distributed in the hope that it will be useful, |
9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
11 | GNU General Public License for more details. |
12 | |
13 | You should have received a copy of the GNU General Public License |
14 | along with this program; if not, write to the Free Software |
15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
16 | |
17 | #include "mariadb.h" |
18 | #include "item_inetfunc.h" |
19 | |
20 | #include "my_net.h" |
21 | |
22 | /////////////////////////////////////////////////////////////////////////// |
23 | |
24 | static const int IN_ADDR_SIZE= sizeof (in_addr); |
25 | static const int IN6_ADDR_SIZE= sizeof (in6_addr); |
26 | static const int IN6_ADDR_NUM_WORDS= IN6_ADDR_SIZE / 2; |
27 | |
28 | static const char HEX_DIGITS[]= "0123456789abcdef" ; |
29 | |
30 | /////////////////////////////////////////////////////////////////////////// |
31 | |
32 | longlong Item_func_inet_aton::val_int() |
33 | { |
34 | DBUG_ASSERT(fixed); |
35 | |
36 | uint byte_result= 0; |
37 | ulonglong result= 0; // We are ready for 64 bit addresses |
38 | const char *p,* end; |
39 | char c= '.'; // we mark c to indicate invalid IP in case length is 0 |
40 | int dot_count= 0; |
41 | |
42 | StringBuffer<36> tmp; |
43 | String *s= args[0]->val_str_ascii(&tmp); |
44 | |
45 | if (!s) // If null value |
46 | goto err; |
47 | |
48 | null_value= 0; |
49 | |
50 | end= (p = s->ptr()) + s->length(); |
51 | while (p < end) |
52 | { |
53 | c= *p++; |
54 | int digit= (int) (c - '0'); |
55 | if (digit >= 0 && digit <= 9) |
56 | { |
57 | if ((byte_result= byte_result * 10 + digit) > 255) |
58 | goto err; // Wrong address |
59 | } |
60 | else if (c == '.') |
61 | { |
62 | dot_count++; |
63 | result= (result << 8) + (ulonglong) byte_result; |
64 | byte_result= 0; |
65 | } |
66 | else |
67 | goto err; // Invalid character |
68 | } |
69 | if (c != '.') // IP number can't end on '.' |
70 | { |
71 | /* |
72 | Attempt to support short forms of IP-addresses. It's however pretty |
73 | basic one comparing to the BSD support. |
74 | Examples: |
75 | 127 -> 0.0.0.127 |
76 | 127.255 -> 127.0.0.255 |
77 | 127.256 -> NULL (should have been 127.0.1.0) |
78 | 127.2.1 -> 127.2.0.1 |
79 | */ |
80 | switch (dot_count) { |
81 | case 1: result<<= 8; /* Fall through */ |
82 | case 2: result<<= 8; /* Fall through */ |
83 | } |
84 | return (result << 8) + (ulonglong) byte_result; |
85 | } |
86 | |
87 | err: |
88 | null_value=1; |
89 | return 0; |
90 | } |
91 | |
92 | /////////////////////////////////////////////////////////////////////////// |
93 | |
94 | String* Item_func_inet_ntoa::val_str(String* str) |
95 | { |
96 | DBUG_ASSERT(fixed); |
97 | |
98 | ulonglong n= (ulonglong) args[0]->val_int(); |
99 | |
100 | /* |
101 | We do not know if args[0] is NULL until we have called |
102 | some val function on it if args[0] is not a constant! |
103 | |
104 | Also return null if n > 255.255.255.255 |
105 | */ |
106 | if ((null_value= (args[0]->null_value || n > 0xffffffff))) |
107 | return 0; // Null value |
108 | |
109 | str->set_charset(collation.collation); |
110 | str->length(0); |
111 | |
112 | uchar buf[8]; |
113 | int4store(buf, n); |
114 | |
115 | /* Now we can assume little endian. */ |
116 | |
117 | char num[4]; |
118 | num[3]= '.'; |
119 | |
120 | for (uchar *p= buf + 4; p-- > buf;) |
121 | { |
122 | uint c= *p; |
123 | uint n1, n2; // Try to avoid divisions |
124 | n1= c / 100; // 100 digits |
125 | c-= n1 * 100; |
126 | n2= c / 10; // 10 digits |
127 | c-= n2 * 10; // last digit |
128 | num[0]= (char) n1 + '0'; |
129 | num[1]= (char) n2 + '0'; |
130 | num[2]= (char) c + '0'; |
131 | uint length= (n1 ? 4 : n2 ? 3 : 2); // Remove pre-zero |
132 | uint dot_length= (p <= buf) ? 1 : 0; |
133 | (void) str->append(num + 4 - length, length - dot_length, |
134 | &my_charset_latin1); |
135 | } |
136 | |
137 | return str; |
138 | } |
139 | |
140 | /////////////////////////////////////////////////////////////////////////// |
141 | |
142 | /** |
143 | Check the function argument, handle errors properly. |
144 | |
145 | @return The function value. |
146 | */ |
147 | |
148 | longlong Item_func_inet_bool_base::val_int() |
149 | { |
150 | DBUG_ASSERT(fixed); |
151 | |
152 | // String argument expected |
153 | if (unlikely(args[0]->result_type() != STRING_RESULT)) |
154 | return 0; |
155 | |
156 | String buffer; |
157 | String *arg_str= args[0]->val_str(&buffer); |
158 | |
159 | if (unlikely(!arg_str)) // Out-of memory happened. error has been reported. |
160 | return 0; // Or: the underlying field is NULL |
161 | |
162 | return calc_value(arg_str) ? 1 : 0; |
163 | } |
164 | |
165 | /////////////////////////////////////////////////////////////////////////// |
166 | |
167 | /** |
168 | Check the function argument, handle errors properly. |
169 | |
170 | @param [out] buffer Buffer for string operations. |
171 | |
172 | @return The function value. |
173 | */ |
174 | |
175 | String *Item_func_inet_str_base::val_str_ascii(String *buffer) |
176 | { |
177 | DBUG_ASSERT(fixed); |
178 | |
179 | // String argument expected |
180 | if (unlikely(args[0]->result_type() != STRING_RESULT)) |
181 | { |
182 | null_value= true; |
183 | return NULL; |
184 | } |
185 | |
186 | StringBuffer<STRING_BUFFER_USUAL_SIZE> tmp; |
187 | String *arg_str= args[0]->val_str(&tmp); |
188 | if (unlikely(!arg_str)) |
189 | { |
190 | // Out-of memory happened. error has been reported. |
191 | // Or: the underlying field is NULL |
192 | null_value= true; |
193 | return NULL; |
194 | } |
195 | |
196 | null_value= !calc_value(arg_str, buffer); |
197 | |
198 | return unlikely(null_value) ? NULL : buffer; |
199 | } |
200 | |
201 | /////////////////////////////////////////////////////////////////////////// |
202 | |
203 | /** |
204 | Tries to convert given string to binary IPv4-address representation. |
205 | This is a portable alternative to inet_pton(AF_INET). |
206 | |
207 | @param str String to convert. |
208 | @param str_len String length. |
209 | @param[out] ipv4_address Buffer to store IPv4-address. |
210 | |
211 | @return Completion status. |
212 | @retval false Given string does not represent an IPv4-address. |
213 | @retval true The string has been converted sucessfully. |
214 | |
215 | @note The problem with inet_pton() is that it treats leading zeros in |
216 | IPv4-part differently on different platforms. |
217 | */ |
218 | |
219 | static bool str_to_ipv4(const char *str, size_t str_length, in_addr *ipv4_address) |
220 | { |
221 | if (str_length < 7) |
222 | { |
223 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): " |
224 | "invalid IPv4 address: too short." , |
225 | (int) str_length, str)); |
226 | return false; |
227 | } |
228 | |
229 | if (str_length > 15) |
230 | { |
231 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): " |
232 | "invalid IPv4 address: too long." , |
233 | (int) str_length, str)); |
234 | return false; |
235 | } |
236 | |
237 | unsigned char *ipv4_bytes= (unsigned char *) ipv4_address; |
238 | const char *p= str; |
239 | int byte_value= 0; |
240 | int chars_in_group= 0; |
241 | int dot_count= 0; |
242 | char c= 0; |
243 | |
244 | while (((p - str) < (int)str_length) && *p) |
245 | { |
246 | c= *p++; |
247 | |
248 | if (my_isdigit(&my_charset_latin1, c)) |
249 | { |
250 | ++chars_in_group; |
251 | |
252 | if (chars_in_group > 3) |
253 | { |
254 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
255 | "too many characters in a group." , |
256 | (int) str_length, str)); |
257 | return false; |
258 | } |
259 | |
260 | byte_value= byte_value * 10 + (c - '0'); |
261 | |
262 | if (byte_value > 255) |
263 | { |
264 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
265 | "invalid byte value." , |
266 | (int) str_length, str)); |
267 | return false; |
268 | } |
269 | } |
270 | else if (c == '.') |
271 | { |
272 | if (chars_in_group == 0) |
273 | { |
274 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
275 | "too few characters in a group." , |
276 | (int) str_length, str)); |
277 | return false; |
278 | } |
279 | |
280 | ipv4_bytes[dot_count]= (unsigned char) byte_value; |
281 | |
282 | ++dot_count; |
283 | byte_value= 0; |
284 | chars_in_group= 0; |
285 | |
286 | if (dot_count > 3) |
287 | { |
288 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
289 | "too many dots." , (int) str_length, str)); |
290 | return false; |
291 | } |
292 | } |
293 | else |
294 | { |
295 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
296 | "invalid character at pos %d." , |
297 | (int) str_length, str, (int) (p - str))); |
298 | return false; |
299 | } |
300 | } |
301 | |
302 | if (c == '.') |
303 | { |
304 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
305 | "ending at '.'." , (int) str_length, str)); |
306 | return false; |
307 | } |
308 | |
309 | if (dot_count != 3) |
310 | { |
311 | DBUG_PRINT("error" , ("str_to_ipv4(%.*s): invalid IPv4 address: " |
312 | "too few groups." , |
313 | (int) str_length, str)); |
314 | return false; |
315 | } |
316 | |
317 | ipv4_bytes[3]= (unsigned char) byte_value; |
318 | |
319 | DBUG_PRINT("info" , ("str_to_ipv4(%.*s): valid IPv4 address: %d.%d.%d.%d" , |
320 | (int) str_length, str, |
321 | ipv4_bytes[0], ipv4_bytes[1], |
322 | ipv4_bytes[2], ipv4_bytes[3])); |
323 | return true; |
324 | } |
325 | |
326 | /////////////////////////////////////////////////////////////////////////// |
327 | |
328 | /** |
329 | Tries to convert given string to binary IPv6-address representation. |
330 | This is a portable alternative to inet_pton(AF_INET6). |
331 | |
332 | @param str String to convert. |
333 | @param str_len String length. |
334 | @param[out] ipv6_address Buffer to store IPv6-address. |
335 | |
336 | @return Completion status. |
337 | @retval false Given string does not represent an IPv6-address. |
338 | @retval true The string has been converted sucessfully. |
339 | |
340 | @note The problem with inet_pton() is that it treats leading zeros in |
341 | IPv4-part differently on different platforms. |
342 | */ |
343 | |
344 | static bool str_to_ipv6(const char *str, int str_length, in6_addr *ipv6_address) |
345 | { |
346 | if (str_length < 2) |
347 | { |
348 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: too short." , |
349 | str_length, str)); |
350 | return false; |
351 | } |
352 | |
353 | if (str_length > 8 * 4 + 7) |
354 | { |
355 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: too long." , |
356 | str_length, str)); |
357 | return false; |
358 | } |
359 | |
360 | memset(ipv6_address, 0, IN6_ADDR_SIZE); |
361 | |
362 | const char *p= str; |
363 | |
364 | if (*p == ':') |
365 | { |
366 | ++p; |
367 | |
368 | if (*p != ':') |
369 | { |
370 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
371 | "can not start with ':x'." , str_length, str)); |
372 | return false; |
373 | } |
374 | } |
375 | |
376 | char *ipv6_bytes= (char *) ipv6_address; |
377 | char *ipv6_bytes_end= ipv6_bytes + IN6_ADDR_SIZE; |
378 | char *dst= ipv6_bytes; |
379 | char *gap_ptr= NULL; |
380 | const char *group_start_ptr= p; |
381 | int chars_in_group= 0; |
382 | int group_value= 0; |
383 | |
384 | while (((p - str) < str_length) && *p) |
385 | { |
386 | char c= *p++; |
387 | |
388 | if (c == ':') |
389 | { |
390 | group_start_ptr= p; |
391 | |
392 | if (!chars_in_group) |
393 | { |
394 | if (gap_ptr) |
395 | { |
396 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
397 | "too many gaps(::)." , str_length, str)); |
398 | return false; |
399 | } |
400 | |
401 | gap_ptr= dst; |
402 | continue; |
403 | } |
404 | |
405 | if (!*p || ((p - str) >= str_length)) |
406 | { |
407 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
408 | "ending at ':'." , str_length, str)); |
409 | return false; |
410 | } |
411 | |
412 | if (dst + 2 > ipv6_bytes_end) |
413 | { |
414 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
415 | "too many groups (1)." , str_length, str)); |
416 | return false; |
417 | } |
418 | |
419 | dst[0]= (unsigned char) (group_value >> 8) & 0xff; |
420 | dst[1]= (unsigned char) group_value & 0xff; |
421 | dst += 2; |
422 | |
423 | chars_in_group= 0; |
424 | group_value= 0; |
425 | } |
426 | else if (c == '.') |
427 | { |
428 | if (dst + IN_ADDR_SIZE > ipv6_bytes_end) |
429 | { |
430 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
431 | "unexpected IPv4-part." , str_length, str)); |
432 | return false; |
433 | } |
434 | |
435 | if (!str_to_ipv4(group_start_ptr, |
436 | str + str_length - group_start_ptr, |
437 | (in_addr *) dst)) |
438 | { |
439 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
440 | "invalid IPv4-part." , str_length, str)); |
441 | return false; |
442 | } |
443 | |
444 | dst += IN_ADDR_SIZE; |
445 | chars_in_group= 0; |
446 | |
447 | break; |
448 | } |
449 | else |
450 | { |
451 | const char *hdp= strchr(HEX_DIGITS, my_tolower(&my_charset_latin1, c)); |
452 | |
453 | if (!hdp) |
454 | { |
455 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
456 | "invalid character at pos %d." , |
457 | str_length, str, (int) (p - str))); |
458 | return false; |
459 | } |
460 | |
461 | if (chars_in_group >= 4) |
462 | { |
463 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
464 | "too many digits in group." , |
465 | str_length, str)); |
466 | return false; |
467 | } |
468 | |
469 | group_value <<= 4; |
470 | group_value |= hdp - HEX_DIGITS; |
471 | |
472 | DBUG_ASSERT(group_value <= 0xffff); |
473 | |
474 | ++chars_in_group; |
475 | } |
476 | } |
477 | |
478 | if (chars_in_group > 0) |
479 | { |
480 | if (dst + 2 > ipv6_bytes_end) |
481 | { |
482 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
483 | "too many groups (2)." , str_length, str)); |
484 | return false; |
485 | } |
486 | |
487 | dst[0]= (unsigned char) (group_value >> 8) & 0xff; |
488 | dst[1]= (unsigned char) group_value & 0xff; |
489 | dst += 2; |
490 | } |
491 | |
492 | if (gap_ptr) |
493 | { |
494 | if (dst == ipv6_bytes_end) |
495 | { |
496 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
497 | "no room for a gap (::)." , str_length, str)); |
498 | return false; |
499 | } |
500 | |
501 | int bytes_to_move= (int)(dst - gap_ptr); |
502 | |
503 | for (int i= 1; i <= bytes_to_move; ++i) |
504 | { |
505 | ipv6_bytes_end[-i]= gap_ptr[bytes_to_move - i]; |
506 | gap_ptr[bytes_to_move - i]= 0; |
507 | } |
508 | |
509 | dst= ipv6_bytes_end; |
510 | } |
511 | |
512 | if (dst < ipv6_bytes_end) |
513 | { |
514 | DBUG_PRINT("error" , ("str_to_ipv6(%.*s): invalid IPv6 address: " |
515 | "too few groups." , str_length, str)); |
516 | return false; |
517 | } |
518 | |
519 | return true; |
520 | } |
521 | |
522 | /////////////////////////////////////////////////////////////////////////// |
523 | |
524 | /** |
525 | Converts IPv4-binary-address to a string. This function is a portable |
526 | alternative to inet_ntop(AF_INET). |
527 | |
528 | @param[in] ipv4 IPv4-address data (byte array) |
529 | @param[out] str A buffer to store string representation of IPv4-address. |
530 | It must be at least of INET_ADDRSTRLEN. |
531 | |
532 | @note The problem with inet_ntop() is that it is available starting from |
533 | Windows Vista, but the minimum supported version is Windows 2000. |
534 | */ |
535 | |
536 | static void ipv4_to_str(const in_addr *ipv4, char *str) |
537 | { |
538 | const unsigned char *ipv4_bytes= (const unsigned char *) ipv4; |
539 | |
540 | sprintf(str, "%d.%d.%d.%d" , |
541 | ipv4_bytes[0], ipv4_bytes[1], ipv4_bytes[2], ipv4_bytes[3]); |
542 | } |
543 | /////////////////////////////////////////////////////////////////////////// |
544 | |
545 | /** |
546 | Converts IPv6-binary-address to a string. This function is a portable |
547 | alternative to inet_ntop(AF_INET6). |
548 | |
549 | @param[in] ipv6 IPv6-address data (byte array) |
550 | @param[out] str A buffer to store string representation of IPv6-address. |
551 | It must be at least of INET6_ADDRSTRLEN. |
552 | |
553 | @note The problem with inet_ntop() is that it is available starting from |
554 | Windows Vista, but out the minimum supported version is Windows 2000. |
555 | */ |
556 | |
557 | static void ipv6_to_str(const in6_addr *ipv6, char *str) |
558 | { |
559 | struct Region |
560 | { |
561 | int pos; |
562 | int length; |
563 | }; |
564 | |
565 | const unsigned char *ipv6_bytes= (const unsigned char *) ipv6; |
566 | |
567 | // 1. Translate IPv6-address bytes to words. |
568 | // We can't just cast to short, because it's not guaranteed |
569 | // that sizeof (short) == 2. So, we have to make a copy. |
570 | |
571 | uint16 ipv6_words[IN6_ADDR_NUM_WORDS]; |
572 | |
573 | for (int i= 0; i < IN6_ADDR_NUM_WORDS; ++i) |
574 | ipv6_words[i]= (ipv6_bytes[2 * i] << 8) + ipv6_bytes[2 * i + 1]; |
575 | |
576 | // 2. Find "the gap" -- longest sequence of zeros in IPv6-address. |
577 | |
578 | Region gap= { -1, -1 }; |
579 | |
580 | { |
581 | Region rg= { -1, -1 }; |
582 | |
583 | for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i) |
584 | { |
585 | if (ipv6_words[i] != 0) |
586 | { |
587 | if (rg.pos >= 0) |
588 | { |
589 | if (rg.length > gap.length) |
590 | gap= rg; |
591 | |
592 | rg.pos= -1; |
593 | rg.length= -1; |
594 | } |
595 | } |
596 | else |
597 | { |
598 | if (rg.pos >= 0) |
599 | { |
600 | ++rg.length; |
601 | } |
602 | else |
603 | { |
604 | rg.pos= i; |
605 | rg.length= 1; |
606 | } |
607 | } |
608 | } |
609 | |
610 | if (rg.pos >= 0) |
611 | { |
612 | if (rg.length > gap.length) |
613 | gap= rg; |
614 | } |
615 | } |
616 | |
617 | // 3. Convert binary data to string. |
618 | |
619 | char *p= str; |
620 | |
621 | for (int i = 0; i < IN6_ADDR_NUM_WORDS; ++i) |
622 | { |
623 | if (i == gap.pos) |
624 | { |
625 | // We're at the gap position. We should put trailing ':' and jump to |
626 | // the end of the gap. |
627 | |
628 | if (i == 0) |
629 | { |
630 | // The gap starts from the beginning of the data -- leading ':' |
631 | // should be put additionally. |
632 | |
633 | *p= ':'; |
634 | ++p; |
635 | } |
636 | |
637 | *p= ':'; |
638 | ++p; |
639 | |
640 | i += gap.length - 1; |
641 | } |
642 | else if (i == 6 && gap.pos == 0 && |
643 | (gap.length == 6 || // IPv4-compatible |
644 | (gap.length == 5 && ipv6_words[5] == 0xffff) // IPv4-mapped |
645 | )) |
646 | { |
647 | // The data represents either IPv4-compatible or IPv4-mapped address. |
648 | // The IPv6-part (zeros or zeros + ffff) has been already put into |
649 | // the string (str). Now it's time to dump IPv4-part. |
650 | |
651 | ipv4_to_str((const in_addr *) (ipv6_bytes + 12), p); |
652 | return; |
653 | } |
654 | else |
655 | { |
656 | // Usual IPv6-address-field. Print it out using lower-case |
657 | // hex-letters without leading zeros (recommended IPv6-format). |
658 | // |
659 | // If it is not the last field, append closing ':'. |
660 | |
661 | p += sprintf(p, "%x" , ipv6_words[i]); |
662 | |
663 | if (i != IN6_ADDR_NUM_WORDS - 1) |
664 | { |
665 | *p= ':'; |
666 | ++p; |
667 | } |
668 | } |
669 | } |
670 | |
671 | *p= 0; |
672 | } |
673 | |
674 | /////////////////////////////////////////////////////////////////////////// |
675 | |
676 | /** |
677 | Converts IP-address-string to IP-address-data. |
678 | |
679 | @param arg IP-address-string. |
680 | @param [out] buffer Buffer to store IP-address-data. |
681 | |
682 | @return Completion status. |
683 | @retval false Given string does not represent an IP-address. |
684 | @retval true The string has been converted sucessfully. |
685 | */ |
686 | |
687 | bool Item_func_inet6_aton::calc_value(const String *arg, String *buffer) |
688 | { |
689 | // ipv4-string -> varbinary(4) |
690 | // ipv6-string -> varbinary(16) |
691 | |
692 | in_addr ipv4_address; |
693 | in6_addr ipv6_address; |
694 | |
695 | if (str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address)) |
696 | { |
697 | buffer->length(0); |
698 | buffer->append((char *) &ipv4_address, sizeof (in_addr), &my_charset_bin); |
699 | |
700 | return true; |
701 | } |
702 | |
703 | if (str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address)) |
704 | { |
705 | buffer->length(0); |
706 | buffer->append((char *) &ipv6_address, sizeof (in6_addr), &my_charset_bin); |
707 | |
708 | return true; |
709 | } |
710 | |
711 | return false; |
712 | } |
713 | |
714 | /////////////////////////////////////////////////////////////////////////// |
715 | |
716 | /** |
717 | Converts IP-address-data to IP-address-string. |
718 | |
719 | @param arg IP-address-data. |
720 | @param [out] buffer Buffer to store IP-address-string. |
721 | |
722 | @return Completion status. |
723 | @retval false The argument does not correspond to IP-address. |
724 | @retval true The string has been converted sucessfully. |
725 | */ |
726 | |
727 | bool Item_func_inet6_ntoa::calc_value(const String *arg, String *buffer) |
728 | { |
729 | if (arg->charset() != &my_charset_bin) |
730 | return false; |
731 | |
732 | if ((int) arg->length() == IN_ADDR_SIZE) |
733 | { |
734 | char str[INET_ADDRSTRLEN]; |
735 | |
736 | ipv4_to_str((const in_addr *) arg->ptr(), str); |
737 | |
738 | buffer->length(0); |
739 | buffer->append(str, (uint32) strlen(str), &my_charset_latin1); |
740 | |
741 | return true; |
742 | } |
743 | else if ((int) arg->length() == IN6_ADDR_SIZE) |
744 | { |
745 | char str[INET6_ADDRSTRLEN]; |
746 | |
747 | ipv6_to_str((const in6_addr *) arg->ptr(), str); |
748 | |
749 | buffer->length(0); |
750 | buffer->append(str, (uint32) strlen(str), &my_charset_latin1); |
751 | |
752 | return true; |
753 | } |
754 | |
755 | DBUG_PRINT("info" , |
756 | ("INET6_NTOA(): varbinary(4) or varbinary(16) expected." )); |
757 | return false; |
758 | } |
759 | |
760 | /////////////////////////////////////////////////////////////////////////// |
761 | |
762 | /** |
763 | Checks if the passed string represents an IPv4-address. |
764 | |
765 | @param arg The string to check. |
766 | |
767 | @return Check status. |
768 | @retval false The passed string does not represent an IPv4-address. |
769 | @retval true The passed string represents an IPv4-address. |
770 | */ |
771 | |
772 | bool Item_func_is_ipv4::calc_value(const String *arg) |
773 | { |
774 | in_addr ipv4_address; |
775 | |
776 | return str_to_ipv4(arg->ptr(), arg->length(), &ipv4_address); |
777 | } |
778 | |
779 | /////////////////////////////////////////////////////////////////////////// |
780 | |
781 | /** |
782 | Checks if the passed string represents an IPv6-address. |
783 | |
784 | @param arg The string to check. |
785 | |
786 | @return Check status. |
787 | @retval false The passed string does not represent an IPv6-address. |
788 | @retval true The passed string represents an IPv6-address. |
789 | */ |
790 | |
791 | bool Item_func_is_ipv6::calc_value(const String *arg) |
792 | { |
793 | in6_addr ipv6_address; |
794 | |
795 | return str_to_ipv6(arg->ptr(), arg->length(), &ipv6_address); |
796 | } |
797 | |
798 | /////////////////////////////////////////////////////////////////////////// |
799 | |
800 | /** |
801 | Checks if the passed IPv6-address is an IPv4-compat IPv6-address. |
802 | |
803 | @param arg The IPv6-address to check. |
804 | |
805 | @return Check status. |
806 | @retval false The passed IPv6-address is not an IPv4-compatible IPv6-address. |
807 | @retval true The passed IPv6-address is an IPv4-compatible IPv6-address. |
808 | */ |
809 | |
810 | bool Item_func_is_ipv4_compat::calc_value(const String *arg) |
811 | { |
812 | if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) |
813 | return false; |
814 | |
815 | return IN6_IS_ADDR_V4COMPAT((struct in6_addr *) arg->ptr()); |
816 | } |
817 | |
818 | /////////////////////////////////////////////////////////////////////////// |
819 | |
820 | /** |
821 | Checks if the passed IPv6-address is an IPv4-mapped IPv6-address. |
822 | |
823 | @param arg The IPv6-address to check. |
824 | |
825 | @return Check status. |
826 | @retval false The passed IPv6-address is not an IPv4-mapped IPv6-address. |
827 | @retval true The passed IPv6-address is an IPv4-mapped IPv6-address. |
828 | */ |
829 | |
830 | bool Item_func_is_ipv4_mapped::calc_value(const String *arg) |
831 | { |
832 | if ((int) arg->length() != IN6_ADDR_SIZE || arg->charset() != &my_charset_bin) |
833 | return false; |
834 | |
835 | return IN6_IS_ADDR_V4MAPPED((struct in6_addr *) arg->ptr()); |
836 | } |
837 | |