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