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