LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - inet_net_pton.c (source / functions) Coverage Total Hit UBC CBC
Current: Differential Code Coverage HEAD vs 15 Lines: 73.5 % 275 202 73 202
Current Date: 2023-04-08 15:15:32 Functions: 100.0 % 7 7 7
Baseline: 15
Baseline Date: 2023-04-08 15:09:40
Legend: Lines: hit not hit

           TLA  Line data    Source code
       1                 : /*
       2                 :  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
       3                 :  * Copyright (c) 1996,1999 by Internet Software Consortium.
       4                 :  *
       5                 :  * Permission to use, copy, modify, and distribute this software for any
       6                 :  * purpose with or without fee is hereby granted, provided that the above
       7                 :  * copyright notice and this permission notice appear in all copies.
       8                 :  *
       9                 :  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
      10                 :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11                 :  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
      12                 :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13                 :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14                 :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
      15                 :  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16                 :  *
      17                 :  *    src/backend/utils/adt/inet_net_pton.c
      18                 :  */
      19                 : 
      20                 : #if defined(LIBC_SCCS) && !defined(lint)
      21                 : static const char rcsid[] = "Id: inet_net_pton.c,v 1.4.2.3 2004/03/17 00:40:11 marka Exp $";
      22                 : #endif
      23                 : 
      24                 : #include "postgres.h"
      25                 : 
      26                 : #include <sys/socket.h>
      27                 : #include <netinet/in.h>
      28                 : #include <arpa/inet.h>
      29                 : #include <assert.h>
      30                 : #include <ctype.h>
      31                 : 
      32                 : #include "utils/builtins.h" /* pgrminclude ignore */  /* needed on some
      33                 :                                                          * platforms */
      34                 : #include "utils/inet.h"
      35                 : 
      36                 : 
      37                 : static int  inet_net_pton_ipv4(const char *src, u_char *dst);
      38                 : static int  inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size);
      39                 : static int  inet_net_pton_ipv6(const char *src, u_char *dst);
      40                 : static int  inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size);
      41                 : 
      42                 : 
      43                 : /*
      44                 :  * int
      45                 :  * pg_inet_net_pton(af, src, dst, size)
      46                 :  *  convert network number from presentation to network format.
      47                 :  *  accepts hex octets, hex strings, decimal octets, and /CIDR.
      48                 :  *  "size" is in bytes and describes "dst".
      49                 :  * return:
      50                 :  *  number of bits, either imputed classfully or specified with /CIDR,
      51                 :  *  or -1 if some failure occurred (check errno).  ENOENT means it was
      52                 :  *  not a valid network specification.
      53                 :  * author:
      54                 :  *  Paul Vixie (ISC), June 1996
      55                 :  *
      56                 :  * Changes:
      57                 :  *  I added the inet_cidr_pton function (also from Paul) and changed
      58                 :  *  the names to reflect their current use.
      59                 :  *
      60                 :  */
      61                 : int
      62 CBC        2348 : pg_inet_net_pton(int af, const char *src, void *dst, size_t size)
      63                 : {
      64            2348 :     switch (af)
      65                 :     {
      66            1900 :         case PGSQL_AF_INET:
      67                 :             return size == -1 ?
      68            2455 :                 inet_net_pton_ipv4(src, dst) :
      69             555 :                 inet_cidr_pton_ipv4(src, dst, size);
      70             448 :         case PGSQL_AF_INET6:
      71                 :             return size == -1 ?
      72             592 :                 inet_net_pton_ipv6(src, dst) :
      73             144 :                 inet_cidr_pton_ipv6(src, dst, size);
      74 UBC           0 :         default:
      75               0 :             errno = EAFNOSUPPORT;
      76               0 :             return -1;
      77                 :     }
      78                 : }
      79                 : 
      80                 : /*
      81                 :  * static int
      82                 :  * inet_cidr_pton_ipv4(src, dst, size)
      83                 :  *  convert IPv4 network number from presentation to network format.
      84                 :  *  accepts hex octets, hex strings, decimal octets, and /CIDR.
      85                 :  *  "size" is in bytes and describes "dst".
      86                 :  * return:
      87                 :  *  number of bits, either imputed classfully or specified with /CIDR,
      88                 :  *  or -1 if some failure occurred (check errno).  ENOENT means it was
      89                 :  *  not an IPv4 network specification.
      90                 :  * note:
      91                 :  *  network byte order assumed.  this means 192.5.5.240/28 has
      92                 :  *  0b11110000 in its fourth octet.
      93                 :  * author:
      94                 :  *  Paul Vixie (ISC), June 1996
      95                 :  */
      96                 : static int
      97 CBC         555 : inet_cidr_pton_ipv4(const char *src, u_char *dst, size_t size)
      98                 : {
      99                 :     static const char xdigits[] = "0123456789abcdef";
     100                 :     static const char digits[] = "0123456789";
     101                 :     int         n,
     102                 :                 ch,
     103             555 :                 tmp = 0,
     104                 :                 dirty,
     105                 :                 bits;
     106             555 :     const u_char *odst = dst;
     107                 : 
     108             555 :     ch = *src++;
     109             555 :     if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
     110 UBC           0 :         && isxdigit((unsigned char) src[1]))
     111                 :     {
     112                 :         /* Hexadecimal: Eat nybble string. */
     113               0 :         if (size <= 0U)
     114               0 :             goto emsgsize;
     115               0 :         dirty = 0;
     116               0 :         src++;                  /* skip x or X. */
     117               0 :         while ((ch = *src++) != '\0' && isxdigit((unsigned char) ch))
     118                 :         {
     119               0 :             if (isupper((unsigned char) ch))
     120               0 :                 ch = tolower((unsigned char) ch);
     121               0 :             n = strchr(xdigits, ch) - xdigits;
     122               0 :             assert(n >= 0 && n <= 15);
     123               0 :             if (dirty == 0)
     124               0 :                 tmp = n;
     125                 :             else
     126               0 :                 tmp = (tmp << 4) | n;
     127               0 :             if (++dirty == 2)
     128                 :             {
     129               0 :                 if (size-- <= 0U)
     130               0 :                     goto emsgsize;
     131               0 :                 *dst++ = (u_char) tmp;
     132               0 :                 dirty = 0;
     133                 :             }
     134                 :         }
     135               0 :         if (dirty)
     136                 :         {                       /* Odd trailing nybble? */
     137               0 :             if (size-- <= 0U)
     138               0 :                 goto emsgsize;
     139               0 :             *dst++ = (u_char) (tmp << 4);
     140                 :         }
     141                 :     }
     142 CBC         555 :     else if (isdigit((unsigned char) ch))
     143                 :     {
     144                 :         /* Decimal: eat dotted digit string. */
     145                 :         for (;;)
     146                 :         {
     147            1815 :             tmp = 0;
     148                 :             do
     149                 :             {
     150            3490 :                 n = strchr(digits, ch) - digits;
     151            3490 :                 assert(n >= 0 && n <= 9);
     152            3490 :                 tmp *= 10;
     153            3490 :                 tmp += n;
     154            3490 :                 if (tmp > 255)
     155               6 :                     goto enoent;
     156            3484 :             } while ((ch = *src++) != '\0' &&
     157            3234 :                      isdigit((unsigned char) ch));
     158            1809 :             if (size-- <= 0U)
     159 UBC           0 :                 goto emsgsize;
     160 CBC        1809 :             *dst++ = (u_char) tmp;
     161            1809 :             if (ch == '\0' || ch == '/')
     162                 :                 break;
     163            1260 :             if (ch != '.')
     164 UBC           0 :                 goto enoent;
     165 CBC        1260 :             ch = *src++;
     166            1260 :             if (!isdigit((unsigned char) ch))
     167 UBC           0 :                 goto enoent;
     168                 :         }
     169                 :     }
     170                 :     else
     171               0 :         goto enoent;
     172                 : 
     173 CBC         549 :     bits = -1;
     174             549 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     175                 :     {
     176                 :         /* CIDR width specifier.  Nothing can follow it. */
     177             299 :         ch = *src++;            /* Skip over the /. */
     178             299 :         bits = 0;
     179                 :         do
     180                 :         {
     181             523 :             n = strchr(digits, ch) - digits;
     182             523 :             assert(n >= 0 && n <= 9);
     183             523 :             bits *= 10;
     184             523 :             bits += n;
     185             523 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     186             299 :         if (ch != '\0')
     187 UBC           0 :             goto enoent;
     188 CBC         299 :         if (bits > 32)
     189 UBC           0 :             goto emsgsize;
     190                 :     }
     191                 : 
     192                 :     /* Fiery death and destruction unless we prefetched EOS. */
     193 CBC         549 :     if (ch != '\0')
     194 UBC           0 :         goto enoent;
     195                 : 
     196                 :     /* If nothing was written to the destination, we found no address. */
     197 CBC         549 :     if (dst == odst)
     198 UBC           0 :         goto enoent;
     199                 :     /* If no CIDR spec was given, infer width from net class. */
     200 CBC         549 :     if (bits == -1)
     201                 :     {
     202             250 :         if (*odst >= 240)        /* Class E */
     203              96 :             bits = 32;
     204             154 :         else if (*odst >= 224)   /* Class D */
     205 UBC           0 :             bits = 8;
     206 CBC         154 :         else if (*odst >= 192)   /* Class C */
     207              15 :             bits = 24;
     208             139 :         else if (*odst >= 128)   /* Class B */
     209 UBC           0 :             bits = 16;
     210                 :         else
     211                 :             /* Class A */
     212 CBC         139 :             bits = 8;
     213                 :         /* If imputed mask is narrower than specified octets, widen. */
     214             250 :         if (bits < ((dst - odst) * 8))
     215             124 :             bits = (dst - odst) * 8;
     216                 : 
     217                 :         /*
     218                 :          * If there are no additional bits specified for a class D address
     219                 :          * adjust bits to 4.
     220                 :          */
     221             250 :         if (bits == 8 && *odst == 224)
     222 UBC           0 :             bits = 4;
     223                 :     }
     224                 :     /* Extend network to cover the actual mask. */
     225 CBC         573 :     while (bits > ((dst - odst) * 8))
     226                 :     {
     227              24 :         if (size-- <= 0U)
     228 UBC           0 :             goto emsgsize;
     229 CBC          24 :         *dst++ = '\0';
     230                 :     }
     231             549 :     return bits;
     232                 : 
     233               6 : enoent:
     234               6 :     errno = ENOENT;
     235               6 :     return -1;
     236                 : 
     237 UBC           0 : emsgsize:
     238               0 :     errno = EMSGSIZE;
     239               0 :     return -1;
     240                 : }
     241                 : 
     242                 : /*
     243                 :  * int
     244                 :  * inet_net_pton_ipv4(af, src, dst, *bits)
     245                 :  *  convert network address from presentation to network format.
     246                 :  *  accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
     247                 :  *  "dst" is assumed large enough for its "af".  "bits" is set to the
     248                 :  *  /CIDR prefix length, which can have defaults (like /32 for IPv4).
     249                 :  * return:
     250                 :  *  -1 if an error occurred (inspect errno; ENOENT means bad format).
     251                 :  *  0 if successful conversion occurred.
     252                 :  * note:
     253                 :  *  192.5.5.1/28 has a nonzero host part, which means it isn't a network
     254                 :  *  as called for by inet_cidr_pton() but it can be a host address with
     255                 :  *  an included netmask.
     256                 :  * author:
     257                 :  *  Paul Vixie (ISC), October 1998
     258                 :  */
     259                 : static int
     260 CBC        1345 : inet_net_pton_ipv4(const char *src, u_char *dst)
     261                 : {
     262                 :     static const char digits[] = "0123456789";
     263            1345 :     const u_char *odst = dst;
     264                 :     int         n,
     265                 :                 ch,
     266                 :                 tmp,
     267                 :                 bits;
     268            1345 :     size_t      size = 4;
     269                 : 
     270                 :     /* Get the mantissa. */
     271            5182 :     while (ch = *src++, isdigit((unsigned char) ch))
     272                 :     {
     273            5182 :         tmp = 0;
     274                 :         do
     275                 :         {
     276           11731 :             n = strchr(digits, ch) - digits;
     277           11731 :             assert(n >= 0 && n <= 9);
     278           11731 :             tmp *= 10;
     279           11731 :             tmp += n;
     280           11731 :             if (tmp > 255)
     281               6 :                 goto enoent;
     282           11725 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     283            5176 :         if (size-- == 0)
     284 UBC           0 :             goto emsgsize;
     285 CBC        5176 :         *dst++ = (u_char) tmp;
     286            5176 :         if (ch == '\0' || ch == '/')
     287                 :             break;
     288            3837 :         if (ch != '.')
     289 UBC           0 :             goto enoent;
     290                 :     }
     291                 : 
     292                 :     /* Get the prefix length if any. */
     293 CBC        1339 :     bits = -1;
     294            1339 :     if (ch == '/' && isdigit((unsigned char) src[0]) && dst > odst)
     295                 :     {
     296                 :         /* CIDR width specifier.  Nothing can follow it. */
     297             469 :         ch = *src++;            /* Skip over the /. */
     298             469 :         bits = 0;
     299                 :         do
     300                 :         {
     301             750 :             n = strchr(digits, ch) - digits;
     302             750 :             assert(n >= 0 && n <= 9);
     303             750 :             bits *= 10;
     304             750 :             bits += n;
     305             750 :         } while ((ch = *src++) != '\0' && isdigit((unsigned char) ch));
     306             469 :         if (ch != '\0')
     307 UBC           0 :             goto enoent;
     308 CBC         469 :         if (bits > 32)
     309 UBC           0 :             goto emsgsize;
     310                 :     }
     311                 : 
     312                 :     /* Fiery death and destruction unless we prefetched EOS. */
     313 CBC        1339 :     if (ch != '\0')
     314 UBC           0 :         goto enoent;
     315                 : 
     316                 :     /* Prefix length can default to /32 only if all four octets spec'd. */
     317 CBC        1339 :     if (bits == -1)
     318                 :     {
     319             870 :         if (dst - odst == 4)
     320             870 :             bits = 32;
     321                 :         else
     322 UBC           0 :             goto enoent;
     323                 :     }
     324                 : 
     325                 :     /* If nothing was written to the destination, we found no address. */
     326 CBC        1339 :     if (dst == odst)
     327 UBC           0 :         goto enoent;
     328                 : 
     329                 :     /* If prefix length overspecifies mantissa, life is bad. */
     330 CBC        1339 :     if ((bits / 8) > (dst - odst))
     331 UBC           0 :         goto enoent;
     332                 : 
     333                 :     /* Extend address to four octets. */
     334 CBC        1519 :     while (size-- > 0)
     335             180 :         *dst++ = 0;
     336                 : 
     337            1339 :     return bits;
     338                 : 
     339               6 : enoent:
     340               6 :     errno = ENOENT;
     341               6 :     return -1;
     342                 : 
     343 UBC           0 : emsgsize:
     344               0 :     errno = EMSGSIZE;
     345               0 :     return -1;
     346                 : }
     347                 : 
     348                 : static int
     349 CBC         238 : getbits(const char *src, int *bitsp)
     350                 : {
     351                 :     static const char digits[] = "0123456789";
     352                 :     int         n;
     353                 :     int         val;
     354                 :     char        ch;
     355                 : 
     356             238 :     val = 0;
     357             238 :     n = 0;
     358             712 :     while ((ch = *src++) != '\0')
     359                 :     {
     360                 :         const char *pch;
     361                 : 
     362             474 :         pch = strchr(digits, ch);
     363             474 :         if (pch != NULL)
     364                 :         {
     365             474 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     366 UBC           0 :                 return 0;
     367 CBC         474 :             val *= 10;
     368             474 :             val += (pch - digits);
     369             474 :             if (val > 128)       /* range */
     370 UBC           0 :                 return 0;
     371 CBC         474 :             continue;
     372                 :         }
     373 UBC           0 :         return 0;
     374                 :     }
     375 CBC         238 :     if (n == 0)
     376 UBC           0 :         return 0;
     377 CBC         238 :     *bitsp = val;
     378             238 :     return 1;
     379                 : }
     380                 : 
     381                 : static int
     382               9 : getv4(const char *src, u_char *dst, int *bitsp)
     383                 : {
     384                 :     static const char digits[] = "0123456789";
     385               9 :     u_char     *odst = dst;
     386                 :     int         n;
     387                 :     u_int       val;
     388                 :     char        ch;
     389                 : 
     390               9 :     val = 0;
     391               9 :     n = 0;
     392              72 :     while ((ch = *src++) != '\0')
     393                 :     {
     394                 :         const char *pch;
     395                 : 
     396              69 :         pch = strchr(digits, ch);
     397              69 :         if (pch != NULL)
     398                 :         {
     399              36 :             if (n++ != 0 && val == 0)   /* no leading zeros */
     400 UBC           0 :                 return 0;
     401 CBC          36 :             val *= 10;
     402              36 :             val += (pch - digits);
     403              36 :             if (val > 255)       /* range */
     404 UBC           0 :                 return 0;
     405 CBC          36 :             continue;
     406                 :         }
     407              33 :         if (ch == '.' || ch == '/')
     408                 :         {
     409              33 :             if (dst - odst > 3) /* too many octets? */
     410 UBC           0 :                 return 0;
     411 CBC          33 :             *dst++ = val;
     412              33 :             if (ch == '/')
     413               6 :                 return getbits(src, bitsp);
     414              27 :             val = 0;
     415              27 :             n = 0;
     416              27 :             continue;
     417                 :         }
     418 UBC           0 :         return 0;
     419                 :     }
     420 CBC           3 :     if (n == 0)
     421 UBC           0 :         return 0;
     422 CBC           3 :     if (dst - odst > 3)          /* too many octets? */
     423 UBC           0 :         return 0;
     424 CBC           3 :     *dst++ = val;
     425               3 :     return 1;
     426                 : }
     427                 : 
     428                 : static int
     429             304 : inet_net_pton_ipv6(const char *src, u_char *dst)
     430                 : {
     431             304 :     return inet_cidr_pton_ipv6(src, dst, 16);
     432                 : }
     433                 : 
     434                 : #define NS_IN6ADDRSZ 16
     435                 : #define NS_INT16SZ 2
     436                 : #define NS_INADDRSZ 4
     437                 : 
     438                 : static int
     439             448 : inet_cidr_pton_ipv6(const char *src, u_char *dst, size_t size)
     440                 : {
     441                 :     static const char xdigits_l[] = "0123456789abcdef",
     442                 :                 xdigits_u[] = "0123456789ABCDEF";
     443                 :     u_char      tmp[NS_IN6ADDRSZ],
     444                 :                *tp,
     445                 :                *endp,
     446                 :                *colonp;
     447                 :     const char *xdigits,
     448                 :                *curtok;
     449                 :     int         ch,
     450                 :                 saw_xdigit;
     451                 :     u_int       val;
     452                 :     int         digits;
     453                 :     int         bits;
     454                 : 
     455             448 :     if (size < NS_IN6ADDRSZ)
     456 UBC           0 :         goto emsgsize;
     457                 : 
     458 CBC         448 :     memset((tp = tmp), '\0', NS_IN6ADDRSZ);
     459             448 :     endp = tp + NS_IN6ADDRSZ;
     460             448 :     colonp = NULL;
     461                 :     /* Leading :: requires some special handling. */
     462             448 :     if (*src == ':')
     463              24 :         if (*++src != ':')
     464 UBC           0 :             goto enoent;
     465 CBC         448 :     curtok = src;
     466             448 :     saw_xdigit = 0;
     467             448 :     val = 0;
     468             448 :     digits = 0;
     469             448 :     bits = -1;
     470            9900 :     while ((ch = *src++) != '\0')
     471                 :     {
     472                 :         const char *pch;
     473                 : 
     474            9696 :         if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
     475            2276 :             pch = strchr((xdigits = xdigits_u), ch);
     476            9696 :         if (pch != NULL)
     477                 :         {
     478            7420 :             val <<= 4;
     479            7420 :             val |= (pch - xdigits);
     480            7420 :             if (++digits > 4)
     481 UBC           0 :                 goto enoent;
     482 CBC        7420 :             saw_xdigit = 1;
     483            7420 :             continue;
     484                 :         }
     485            2276 :         if (ch == ':')
     486                 :         {
     487            2035 :             curtok = src;
     488            2035 :             if (!saw_xdigit)
     489                 :             {
     490             360 :                 if (colonp)
     491               3 :                     goto enoent;
     492             357 :                 colonp = tp;
     493             357 :                 continue;
     494                 :             }
     495            1675 :             else if (*src == '\0')
     496 UBC           0 :                 goto enoent;
     497 CBC        1675 :             if (tp + NS_INT16SZ > endp)
     498 UBC           0 :                 goto enoent;
     499 CBC        1675 :             *tp++ = (u_char) (val >> 8) & 0xff;
     500            1675 :             *tp++ = (u_char) val & 0xff;
     501            1675 :             saw_xdigit = 0;
     502            1675 :             digits = 0;
     503            1675 :             val = 0;
     504            1675 :             continue;
     505                 :         }
     506             250 :         if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
     507               9 :             getv4(curtok, tp, &bits) > 0)
     508                 :         {
     509               9 :             tp += NS_INADDRSZ;
     510               9 :             saw_xdigit = 0;
     511               9 :             break;              /* '\0' was seen by inet_pton4(). */
     512                 :         }
     513             232 :         if (ch == '/' && getbits(src, &bits) > 0)
     514             232 :             break;
     515 UBC           0 :         goto enoent;
     516                 :     }
     517 CBC         445 :     if (saw_xdigit)
     518                 :     {
     519             376 :         if (tp + NS_INT16SZ > endp)
     520 UBC           0 :             goto enoent;
     521 CBC         376 :         *tp++ = (u_char) (val >> 8) & 0xff;
     522             376 :         *tp++ = (u_char) val & 0xff;
     523                 :     }
     524             445 :     if (bits == -1)
     525             207 :         bits = 128;
     526                 : 
     527             445 :     endp = tmp + 16;
     528                 : 
     529             445 :     if (colonp != NULL)
     530                 :     {
     531                 :         /*
     532                 :          * Since some memmove()'s erroneously fail to handle overlapping
     533                 :          * regions, we'll do the shift by hand.
     534                 :          */
     535             354 :         const int   n = tp - colonp;
     536                 :         int         i;
     537                 : 
     538             354 :         if (tp == endp)
     539 UBC           0 :             goto enoent;
     540 CBC        2256 :         for (i = 1; i <= n; i++)
     541                 :         {
     542            1902 :             endp[-i] = colonp[n - i];
     543            1902 :             colonp[n - i] = 0;
     544                 :         }
     545             354 :         tp = endp;
     546                 :     }
     547             445 :     if (tp != endp)
     548 UBC           0 :         goto enoent;
     549                 : 
     550                 :     /*
     551                 :      * Copy out the result.
     552                 :      */
     553 CBC         445 :     memcpy(dst, tmp, NS_IN6ADDRSZ);
     554                 : 
     555             445 :     return bits;
     556                 : 
     557               3 : enoent:
     558               3 :     errno = ENOENT;
     559               3 :     return -1;
     560                 : 
     561 UBC           0 : emsgsize:
     562               0 :     errno = EMSGSIZE;
     563               0 :     return -1;
     564                 : }
        

Generated by: LCOV version v1.16-55-g56c0a2a