Header And Logo

PostgreSQL
| The world's most advanced open source database.

network.c

Go to the documentation of this file.
00001 /*
00002  *  PostgreSQL type definitions for the INET and CIDR types.
00003  *
00004  *  src/backend/utils/adt/network.c
00005  *
00006  *  Jon Postel RIP 16 Oct 1998
00007  */
00008 
00009 #include "postgres.h"
00010 
00011 #include <sys/socket.h>
00012 #include <netinet/in.h>
00013 #include <arpa/inet.h>
00014 
00015 #include "access/hash.h"
00016 #include "catalog/pg_type.h"
00017 #include "libpq/ip.h"
00018 #include "libpq/libpq-be.h"
00019 #include "libpq/pqformat.h"
00020 #include "miscadmin.h"
00021 #include "utils/builtins.h"
00022 #include "utils/inet.h"
00023 
00024 
00025 static int32 network_cmp_internal(inet *a1, inet *a2);
00026 static int  bitncmp(void *l, void *r, int n);
00027 static bool addressOK(unsigned char *a, int bits, int family);
00028 static int  ip_addrsize(inet *inetptr);
00029 static inet *internal_inetpl(inet *ip, int64 addend);
00030 
00031 /*
00032  *  Access macros.  We use VARDATA_ANY so that we can process short-header
00033  *  varlena values without detoasting them.  This requires a trick:
00034  *  VARDATA_ANY assumes the varlena header is already filled in, which is
00035  *  not the case when constructing a new value (until SET_INET_VARSIZE is
00036  *  called, which we typically can't do till the end).  Therefore, we
00037  *  always initialize the newly-allocated value to zeroes (using palloc0).
00038  *  A zero length word will look like the not-1-byte case to VARDATA_ANY,
00039  *  and so we correctly construct an uncompressed value.
00040  *
00041  *  Note that ip_maxbits() and SET_INET_VARSIZE() require
00042  *  the family field to be set correctly.
00043  */
00044 
00045 #define ip_family(inetptr) \
00046     (((inet_struct *) VARDATA_ANY(inetptr))->family)
00047 
00048 #define ip_bits(inetptr) \
00049     (((inet_struct *) VARDATA_ANY(inetptr))->bits)
00050 
00051 #define ip_addr(inetptr) \
00052     (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr)
00053 
00054 #define ip_maxbits(inetptr) \
00055     (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128)
00056 
00057 #define SET_INET_VARSIZE(dst) \
00058     SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \
00059                 ip_addrsize(dst))
00060 
00061 
00062 /*
00063  * Return the number of bytes of address storage needed for this data type.
00064  */
00065 static int
00066 ip_addrsize(inet *inetptr)
00067 {
00068     switch (ip_family(inetptr))
00069     {
00070         case PGSQL_AF_INET:
00071             return 4;
00072         case PGSQL_AF_INET6:
00073             return 16;
00074         default:
00075             return 0;
00076     }
00077 }
00078 
00079 /*
00080  * Common INET/CIDR input routine
00081  */
00082 static inet *
00083 network_in(char *src, bool is_cidr)
00084 {
00085     int         bits;
00086     inet       *dst;
00087 
00088     dst = (inet *) palloc0(sizeof(inet));
00089 
00090     /*
00091      * First, check to see if this is an IPv6 or IPv4 address.  IPv6 addresses
00092      * will have a : somewhere in them (several, in fact) so if there is one
00093      * present, assume it's V6, otherwise assume it's V4.
00094      */
00095 
00096     if (strchr(src, ':') != NULL)
00097         ip_family(dst) = PGSQL_AF_INET6;
00098     else
00099         ip_family(dst) = PGSQL_AF_INET;
00100 
00101     bits = inet_net_pton(ip_family(dst), src, ip_addr(dst),
00102                          is_cidr ? ip_addrsize(dst) : -1);
00103     if ((bits < 0) || (bits > ip_maxbits(dst)))
00104         ereport(ERROR,
00105                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00106         /* translator: first %s is inet or cidr */
00107                  errmsg("invalid input syntax for type %s: \"%s\"",
00108                         is_cidr ? "cidr" : "inet", src)));
00109 
00110     /*
00111      * Error check: CIDR values must not have any bits set beyond the masklen.
00112      */
00113     if (is_cidr)
00114     {
00115         if (!addressOK(ip_addr(dst), bits, ip_family(dst)))
00116             ereport(ERROR,
00117                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00118                      errmsg("invalid cidr value: \"%s\"", src),
00119                      errdetail("Value has bits set to right of mask.")));
00120     }
00121 
00122     ip_bits(dst) = bits;
00123     SET_INET_VARSIZE(dst);
00124 
00125     return dst;
00126 }
00127 
00128 Datum
00129 inet_in(PG_FUNCTION_ARGS)
00130 {
00131     char       *src = PG_GETARG_CSTRING(0);
00132 
00133     PG_RETURN_INET_P(network_in(src, false));
00134 }
00135 
00136 Datum
00137 cidr_in(PG_FUNCTION_ARGS)
00138 {
00139     char       *src = PG_GETARG_CSTRING(0);
00140 
00141     PG_RETURN_INET_P(network_in(src, true));
00142 }
00143 
00144 
00145 /*
00146  * Common INET/CIDR output routine
00147  */
00148 static char *
00149 network_out(inet *src, bool is_cidr)
00150 {
00151     char        tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00152     char       *dst;
00153     int         len;
00154 
00155     dst = inet_net_ntop(ip_family(src), ip_addr(src), ip_bits(src),
00156                         tmp, sizeof(tmp));
00157     if (dst == NULL)
00158         ereport(ERROR,
00159                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00160                  errmsg("could not format inet value: %m")));
00161 
00162     /* For CIDR, add /n if not present */
00163     if (is_cidr && strchr(tmp, '/') == NULL)
00164     {
00165         len = strlen(tmp);
00166         snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(src));
00167     }
00168 
00169     return pstrdup(tmp);
00170 }
00171 
00172 Datum
00173 inet_out(PG_FUNCTION_ARGS)
00174 {
00175     inet       *src = PG_GETARG_INET_PP(0);
00176 
00177     PG_RETURN_CSTRING(network_out(src, false));
00178 }
00179 
00180 Datum
00181 cidr_out(PG_FUNCTION_ARGS)
00182 {
00183     inet       *src = PG_GETARG_INET_PP(0);
00184 
00185     PG_RETURN_CSTRING(network_out(src, true));
00186 }
00187 
00188 
00189 /*
00190  *      network_recv        - converts external binary format to inet
00191  *
00192  * The external representation is (one byte apiece for)
00193  * family, bits, is_cidr, address length, address in network byte order.
00194  *
00195  * Presence of is_cidr is largely for historical reasons, though it might
00196  * allow some code-sharing on the client side.  We send it correctly on
00197  * output, but ignore the value on input.
00198  */
00199 static inet *
00200 network_recv(StringInfo buf, bool is_cidr)
00201 {
00202     inet       *addr;
00203     char       *addrptr;
00204     int         bits;
00205     int         nb,
00206                 i;
00207 
00208     /* make sure any unused bits in a CIDR value are zeroed */
00209     addr = (inet *) palloc0(sizeof(inet));
00210 
00211     ip_family(addr) = pq_getmsgbyte(buf);
00212     if (ip_family(addr) != PGSQL_AF_INET &&
00213         ip_family(addr) != PGSQL_AF_INET6)
00214         ereport(ERROR,
00215                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00216         /* translator: %s is inet or cidr */
00217                  errmsg("invalid address family in external \"%s\" value",
00218                         is_cidr ? "cidr" : "inet")));
00219     bits = pq_getmsgbyte(buf);
00220     if (bits < 0 || bits > ip_maxbits(addr))
00221         ereport(ERROR,
00222                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00223         /* translator: %s is inet or cidr */
00224                  errmsg("invalid bits in external \"%s\" value",
00225                         is_cidr ? "cidr" : "inet")));
00226     ip_bits(addr) = bits;
00227     i = pq_getmsgbyte(buf);     /* ignore is_cidr */
00228     nb = pq_getmsgbyte(buf);
00229     if (nb != ip_addrsize(addr))
00230         ereport(ERROR,
00231                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00232         /* translator: %s is inet or cidr */
00233                  errmsg("invalid length in external \"%s\" value",
00234                         is_cidr ? "cidr" : "inet")));
00235 
00236     addrptr = (char *) ip_addr(addr);
00237     for (i = 0; i < nb; i++)
00238         addrptr[i] = pq_getmsgbyte(buf);
00239 
00240     /*
00241      * Error check: CIDR values must not have any bits set beyond the masklen.
00242      */
00243     if (is_cidr)
00244     {
00245         if (!addressOK(ip_addr(addr), bits, ip_family(addr)))
00246             ereport(ERROR,
00247                     (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00248                      errmsg("invalid external \"cidr\" value"),
00249                      errdetail("Value has bits set to right of mask.")));
00250     }
00251 
00252     SET_INET_VARSIZE(addr);
00253 
00254     return addr;
00255 }
00256 
00257 Datum
00258 inet_recv(PG_FUNCTION_ARGS)
00259 {
00260     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00261 
00262     PG_RETURN_INET_P(network_recv(buf, false));
00263 }
00264 
00265 Datum
00266 cidr_recv(PG_FUNCTION_ARGS)
00267 {
00268     StringInfo  buf = (StringInfo) PG_GETARG_POINTER(0);
00269 
00270     PG_RETURN_INET_P(network_recv(buf, true));
00271 }
00272 
00273 
00274 /*
00275  *      network_send        - converts inet to binary format
00276  */
00277 static bytea *
00278 network_send(inet *addr, bool is_cidr)
00279 {
00280     StringInfoData buf;
00281     char       *addrptr;
00282     int         nb,
00283                 i;
00284 
00285     pq_begintypsend(&buf);
00286     pq_sendbyte(&buf, ip_family(addr));
00287     pq_sendbyte(&buf, ip_bits(addr));
00288     pq_sendbyte(&buf, is_cidr);
00289     nb = ip_addrsize(addr);
00290     if (nb < 0)
00291         nb = 0;
00292     pq_sendbyte(&buf, nb);
00293     addrptr = (char *) ip_addr(addr);
00294     for (i = 0; i < nb; i++)
00295         pq_sendbyte(&buf, addrptr[i]);
00296     return pq_endtypsend(&buf);
00297 }
00298 
00299 Datum
00300 inet_send(PG_FUNCTION_ARGS)
00301 {
00302     inet       *addr = PG_GETARG_INET_PP(0);
00303 
00304     PG_RETURN_BYTEA_P(network_send(addr, false));
00305 }
00306 
00307 Datum
00308 cidr_send(PG_FUNCTION_ARGS)
00309 {
00310     inet       *addr = PG_GETARG_INET_PP(0);
00311 
00312     PG_RETURN_BYTEA_P(network_send(addr, true));
00313 }
00314 
00315 
00316 Datum
00317 inet_to_cidr(PG_FUNCTION_ARGS)
00318 {
00319     inet       *src = PG_GETARG_INET_PP(0);
00320     inet       *dst;
00321     int         bits;
00322     int         byte;
00323     int         nbits;
00324     int         maxbytes;
00325 
00326     bits = ip_bits(src);
00327 
00328     /* safety check */
00329     if ((bits < 0) || (bits > ip_maxbits(src)))
00330         elog(ERROR, "invalid inet bit length: %d", bits);
00331 
00332     /* clone the original data */
00333     dst = (inet *) palloc(VARSIZE_ANY(src));
00334     memcpy(dst, src, VARSIZE_ANY(src));
00335 
00336     /* zero out any bits to the right of the netmask */
00337     byte = bits / 8;
00338 
00339     nbits = bits % 8;
00340     /* clear the first byte, this might be a partial byte */
00341     if (nbits != 0)
00342     {
00343         ip_addr(dst)[byte] &= ~(0xFF >> nbits);
00344         byte++;
00345     }
00346     /* clear remaining bytes */
00347     maxbytes = ip_addrsize(dst);
00348     while (byte < maxbytes)
00349     {
00350         ip_addr(dst)[byte] = 0;
00351         byte++;
00352     }
00353 
00354     PG_RETURN_INET_P(dst);
00355 }
00356 
00357 Datum
00358 inet_set_masklen(PG_FUNCTION_ARGS)
00359 {
00360     inet       *src = PG_GETARG_INET_PP(0);
00361     int         bits = PG_GETARG_INT32(1);
00362     inet       *dst;
00363 
00364     if (bits == -1)
00365         bits = ip_maxbits(src);
00366 
00367     if ((bits < 0) || (bits > ip_maxbits(src)))
00368         ereport(ERROR,
00369                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00370                  errmsg("invalid mask length: %d", bits)));
00371 
00372     /* clone the original data */
00373     dst = (inet *) palloc(VARSIZE_ANY(src));
00374     memcpy(dst, src, VARSIZE_ANY(src));
00375 
00376     ip_bits(dst) = bits;
00377 
00378     PG_RETURN_INET_P(dst);
00379 }
00380 
00381 Datum
00382 cidr_set_masklen(PG_FUNCTION_ARGS)
00383 {
00384     inet       *src = PG_GETARG_INET_PP(0);
00385     int         bits = PG_GETARG_INT32(1);
00386     inet       *dst;
00387     int         byte;
00388     int         nbits;
00389     int         maxbytes;
00390 
00391     if (bits == -1)
00392         bits = ip_maxbits(src);
00393 
00394     if ((bits < 0) || (bits > ip_maxbits(src)))
00395         ereport(ERROR,
00396                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00397                  errmsg("invalid mask length: %d", bits)));
00398 
00399     /* clone the original data */
00400     dst = (inet *) palloc(VARSIZE_ANY(src));
00401     memcpy(dst, src, VARSIZE_ANY(src));
00402 
00403     ip_bits(dst) = bits;
00404 
00405     /* zero out any bits to the right of the new netmask */
00406     byte = bits / 8;
00407 
00408     nbits = bits % 8;
00409     /* clear the first byte, this might be a partial byte */
00410     if (nbits != 0)
00411     {
00412         ip_addr(dst)[byte] &= ~(0xFF >> nbits);
00413         byte++;
00414     }
00415     /* clear remaining bytes */
00416     maxbytes = ip_addrsize(dst);
00417     while (byte < maxbytes)
00418     {
00419         ip_addr(dst)[byte] = 0;
00420         byte++;
00421     }
00422 
00423     PG_RETURN_INET_P(dst);
00424 }
00425 
00426 /*
00427  *  Basic comparison function for sorting and inet/cidr comparisons.
00428  *
00429  * Comparison is first on the common bits of the network part, then on
00430  * the length of the network part, and then on the whole unmasked address.
00431  * The effect is that the network part is the major sort key, and for
00432  * equal network parts we sort on the host part.  Note this is only sane
00433  * for CIDR if address bits to the right of the mask are guaranteed zero;
00434  * otherwise logically-equal CIDRs might compare different.
00435  */
00436 
00437 static int32
00438 network_cmp_internal(inet *a1, inet *a2)
00439 {
00440     if (ip_family(a1) == ip_family(a2))
00441     {
00442         int         order;
00443 
00444         order = bitncmp(ip_addr(a1), ip_addr(a2),
00445                         Min(ip_bits(a1), ip_bits(a2)));
00446         if (order != 0)
00447             return order;
00448         order = ((int) ip_bits(a1)) - ((int) ip_bits(a2));
00449         if (order != 0)
00450             return order;
00451         return bitncmp(ip_addr(a1), ip_addr(a2), ip_maxbits(a1));
00452     }
00453 
00454     return ip_family(a1) - ip_family(a2);
00455 }
00456 
00457 Datum
00458 network_cmp(PG_FUNCTION_ARGS)
00459 {
00460     inet       *a1 = PG_GETARG_INET_PP(0);
00461     inet       *a2 = PG_GETARG_INET_PP(1);
00462 
00463     PG_RETURN_INT32(network_cmp_internal(a1, a2));
00464 }
00465 
00466 /*
00467  *  Boolean ordering tests.
00468  */
00469 Datum
00470 network_lt(PG_FUNCTION_ARGS)
00471 {
00472     inet       *a1 = PG_GETARG_INET_PP(0);
00473     inet       *a2 = PG_GETARG_INET_PP(1);
00474 
00475     PG_RETURN_BOOL(network_cmp_internal(a1, a2) < 0);
00476 }
00477 
00478 Datum
00479 network_le(PG_FUNCTION_ARGS)
00480 {
00481     inet       *a1 = PG_GETARG_INET_PP(0);
00482     inet       *a2 = PG_GETARG_INET_PP(1);
00483 
00484     PG_RETURN_BOOL(network_cmp_internal(a1, a2) <= 0);
00485 }
00486 
00487 Datum
00488 network_eq(PG_FUNCTION_ARGS)
00489 {
00490     inet       *a1 = PG_GETARG_INET_PP(0);
00491     inet       *a2 = PG_GETARG_INET_PP(1);
00492 
00493     PG_RETURN_BOOL(network_cmp_internal(a1, a2) == 0);
00494 }
00495 
00496 Datum
00497 network_ge(PG_FUNCTION_ARGS)
00498 {
00499     inet       *a1 = PG_GETARG_INET_PP(0);
00500     inet       *a2 = PG_GETARG_INET_PP(1);
00501 
00502     PG_RETURN_BOOL(network_cmp_internal(a1, a2) >= 0);
00503 }
00504 
00505 Datum
00506 network_gt(PG_FUNCTION_ARGS)
00507 {
00508     inet       *a1 = PG_GETARG_INET_PP(0);
00509     inet       *a2 = PG_GETARG_INET_PP(1);
00510 
00511     PG_RETURN_BOOL(network_cmp_internal(a1, a2) > 0);
00512 }
00513 
00514 Datum
00515 network_ne(PG_FUNCTION_ARGS)
00516 {
00517     inet       *a1 = PG_GETARG_INET_PP(0);
00518     inet       *a2 = PG_GETARG_INET_PP(1);
00519 
00520     PG_RETURN_BOOL(network_cmp_internal(a1, a2) != 0);
00521 }
00522 
00523 /*
00524  * Support function for hash indexes on inet/cidr.
00525  */
00526 Datum
00527 hashinet(PG_FUNCTION_ARGS)
00528 {
00529     inet       *addr = PG_GETARG_INET_PP(0);
00530     int         addrsize = ip_addrsize(addr);
00531 
00532     /* XXX this assumes there are no pad bytes in the data structure */
00533     return hash_any((unsigned char *) VARDATA_ANY(addr), addrsize + 2);
00534 }
00535 
00536 /*
00537  *  Boolean network-inclusion tests.
00538  */
00539 Datum
00540 network_sub(PG_FUNCTION_ARGS)
00541 {
00542     inet       *a1 = PG_GETARG_INET_PP(0);
00543     inet       *a2 = PG_GETARG_INET_PP(1);
00544 
00545     if (ip_family(a1) == ip_family(a2))
00546     {
00547         PG_RETURN_BOOL(ip_bits(a1) > ip_bits(a2)
00548                      && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
00549     }
00550 
00551     PG_RETURN_BOOL(false);
00552 }
00553 
00554 Datum
00555 network_subeq(PG_FUNCTION_ARGS)
00556 {
00557     inet       *a1 = PG_GETARG_INET_PP(0);
00558     inet       *a2 = PG_GETARG_INET_PP(1);
00559 
00560     if (ip_family(a1) == ip_family(a2))
00561     {
00562         PG_RETURN_BOOL(ip_bits(a1) >= ip_bits(a2)
00563                      && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a2)) == 0);
00564     }
00565 
00566     PG_RETURN_BOOL(false);
00567 }
00568 
00569 Datum
00570 network_sup(PG_FUNCTION_ARGS)
00571 {
00572     inet       *a1 = PG_GETARG_INET_PP(0);
00573     inet       *a2 = PG_GETARG_INET_PP(1);
00574 
00575     if (ip_family(a1) == ip_family(a2))
00576     {
00577         PG_RETURN_BOOL(ip_bits(a1) < ip_bits(a2)
00578                      && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
00579     }
00580 
00581     PG_RETURN_BOOL(false);
00582 }
00583 
00584 Datum
00585 network_supeq(PG_FUNCTION_ARGS)
00586 {
00587     inet       *a1 = PG_GETARG_INET_PP(0);
00588     inet       *a2 = PG_GETARG_INET_PP(1);
00589 
00590     if (ip_family(a1) == ip_family(a2))
00591     {
00592         PG_RETURN_BOOL(ip_bits(a1) <= ip_bits(a2)
00593                      && bitncmp(ip_addr(a1), ip_addr(a2), ip_bits(a1)) == 0);
00594     }
00595 
00596     PG_RETURN_BOOL(false);
00597 }
00598 
00599 /*
00600  * Extract data from a network datatype.
00601  */
00602 Datum
00603 network_host(PG_FUNCTION_ARGS)
00604 {
00605     inet       *ip = PG_GETARG_INET_PP(0);
00606     char       *ptr;
00607     char        tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00608 
00609     /* force display of max bits, regardless of masklen... */
00610     if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
00611                       tmp, sizeof(tmp)) == NULL)
00612         ereport(ERROR,
00613                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00614                  errmsg("could not format inet value: %m")));
00615 
00616     /* Suppress /n if present (shouldn't happen now) */
00617     if ((ptr = strchr(tmp, '/')) != NULL)
00618         *ptr = '\0';
00619 
00620     PG_RETURN_TEXT_P(cstring_to_text(tmp));
00621 }
00622 
00623 /*
00624  * network_show implements the inet and cidr casts to text.  This is not
00625  * quite the same behavior as network_out, hence we can't drop it in favor
00626  * of CoerceViaIO.
00627  */
00628 Datum
00629 network_show(PG_FUNCTION_ARGS)
00630 {
00631     inet       *ip = PG_GETARG_INET_PP(0);
00632     int         len;
00633     char        tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00634 
00635     if (inet_net_ntop(ip_family(ip), ip_addr(ip), ip_maxbits(ip),
00636                       tmp, sizeof(tmp)) == NULL)
00637         ereport(ERROR,
00638                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00639                  errmsg("could not format inet value: %m")));
00640 
00641     /* Add /n if not present (which it won't be) */
00642     if (strchr(tmp, '/') == NULL)
00643     {
00644         len = strlen(tmp);
00645         snprintf(tmp + len, sizeof(tmp) - len, "/%u", ip_bits(ip));
00646     }
00647 
00648     PG_RETURN_TEXT_P(cstring_to_text(tmp));
00649 }
00650 
00651 Datum
00652 inet_abbrev(PG_FUNCTION_ARGS)
00653 {
00654     inet       *ip = PG_GETARG_INET_PP(0);
00655     char       *dst;
00656     char        tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00657 
00658     dst = inet_net_ntop(ip_family(ip), ip_addr(ip),
00659                         ip_bits(ip), tmp, sizeof(tmp));
00660 
00661     if (dst == NULL)
00662         ereport(ERROR,
00663                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00664                  errmsg("could not format inet value: %m")));
00665 
00666     PG_RETURN_TEXT_P(cstring_to_text(tmp));
00667 }
00668 
00669 Datum
00670 cidr_abbrev(PG_FUNCTION_ARGS)
00671 {
00672     inet       *ip = PG_GETARG_INET_PP(0);
00673     char       *dst;
00674     char        tmp[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00675 
00676     dst = inet_cidr_ntop(ip_family(ip), ip_addr(ip),
00677                          ip_bits(ip), tmp, sizeof(tmp));
00678 
00679     if (dst == NULL)
00680         ereport(ERROR,
00681                 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
00682                  errmsg("could not format cidr value: %m")));
00683 
00684     PG_RETURN_TEXT_P(cstring_to_text(tmp));
00685 }
00686 
00687 Datum
00688 network_masklen(PG_FUNCTION_ARGS)
00689 {
00690     inet       *ip = PG_GETARG_INET_PP(0);
00691 
00692     PG_RETURN_INT32(ip_bits(ip));
00693 }
00694 
00695 Datum
00696 network_family(PG_FUNCTION_ARGS)
00697 {
00698     inet       *ip = PG_GETARG_INET_PP(0);
00699 
00700     switch (ip_family(ip))
00701     {
00702         case PGSQL_AF_INET:
00703             PG_RETURN_INT32(4);
00704             break;
00705         case PGSQL_AF_INET6:
00706             PG_RETURN_INT32(6);
00707             break;
00708         default:
00709             PG_RETURN_INT32(0);
00710             break;
00711     }
00712 }
00713 
00714 Datum
00715 network_broadcast(PG_FUNCTION_ARGS)
00716 {
00717     inet       *ip = PG_GETARG_INET_PP(0);
00718     inet       *dst;
00719     int         byte;
00720     int         bits;
00721     int         maxbytes;
00722     unsigned char mask;
00723     unsigned char *a,
00724                *b;
00725 
00726     /* make sure any unused bits are zeroed */
00727     dst = (inet *) palloc0(sizeof(inet));
00728 
00729     if (ip_family(ip) == PGSQL_AF_INET)
00730         maxbytes = 4;
00731     else
00732         maxbytes = 16;
00733 
00734     bits = ip_bits(ip);
00735     a = ip_addr(ip);
00736     b = ip_addr(dst);
00737 
00738     for (byte = 0; byte < maxbytes; byte++)
00739     {
00740         if (bits >= 8)
00741         {
00742             mask = 0x00;
00743             bits -= 8;
00744         }
00745         else if (bits == 0)
00746             mask = 0xff;
00747         else
00748         {
00749             mask = 0xff >> bits;
00750             bits = 0;
00751         }
00752 
00753         b[byte] = a[byte] | mask;
00754     }
00755 
00756     ip_family(dst) = ip_family(ip);
00757     ip_bits(dst) = ip_bits(ip);
00758     SET_INET_VARSIZE(dst);
00759 
00760     PG_RETURN_INET_P(dst);
00761 }
00762 
00763 Datum
00764 network_network(PG_FUNCTION_ARGS)
00765 {
00766     inet       *ip = PG_GETARG_INET_PP(0);
00767     inet       *dst;
00768     int         byte;
00769     int         bits;
00770     unsigned char mask;
00771     unsigned char *a,
00772                *b;
00773 
00774     /* make sure any unused bits are zeroed */
00775     dst = (inet *) palloc0(sizeof(inet));
00776 
00777     bits = ip_bits(ip);
00778     a = ip_addr(ip);
00779     b = ip_addr(dst);
00780 
00781     byte = 0;
00782 
00783     while (bits)
00784     {
00785         if (bits >= 8)
00786         {
00787             mask = 0xff;
00788             bits -= 8;
00789         }
00790         else
00791         {
00792             mask = 0xff << (8 - bits);
00793             bits = 0;
00794         }
00795 
00796         b[byte] = a[byte] & mask;
00797         byte++;
00798     }
00799 
00800     ip_family(dst) = ip_family(ip);
00801     ip_bits(dst) = ip_bits(ip);
00802     SET_INET_VARSIZE(dst);
00803 
00804     PG_RETURN_INET_P(dst);
00805 }
00806 
00807 Datum
00808 network_netmask(PG_FUNCTION_ARGS)
00809 {
00810     inet       *ip = PG_GETARG_INET_PP(0);
00811     inet       *dst;
00812     int         byte;
00813     int         bits;
00814     unsigned char mask;
00815     unsigned char *b;
00816 
00817     /* make sure any unused bits are zeroed */
00818     dst = (inet *) palloc0(sizeof(inet));
00819 
00820     bits = ip_bits(ip);
00821     b = ip_addr(dst);
00822 
00823     byte = 0;
00824 
00825     while (bits)
00826     {
00827         if (bits >= 8)
00828         {
00829             mask = 0xff;
00830             bits -= 8;
00831         }
00832         else
00833         {
00834             mask = 0xff << (8 - bits);
00835             bits = 0;
00836         }
00837 
00838         b[byte] = mask;
00839         byte++;
00840     }
00841 
00842     ip_family(dst) = ip_family(ip);
00843     ip_bits(dst) = ip_maxbits(ip);
00844     SET_INET_VARSIZE(dst);
00845 
00846     PG_RETURN_INET_P(dst);
00847 }
00848 
00849 Datum
00850 network_hostmask(PG_FUNCTION_ARGS)
00851 {
00852     inet       *ip = PG_GETARG_INET_PP(0);
00853     inet       *dst;
00854     int         byte;
00855     int         bits;
00856     int         maxbytes;
00857     unsigned char mask;
00858     unsigned char *b;
00859 
00860     /* make sure any unused bits are zeroed */
00861     dst = (inet *) palloc0(sizeof(inet));
00862 
00863     if (ip_family(ip) == PGSQL_AF_INET)
00864         maxbytes = 4;
00865     else
00866         maxbytes = 16;
00867 
00868     bits = ip_maxbits(ip) - ip_bits(ip);
00869     b = ip_addr(dst);
00870 
00871     byte = maxbytes - 1;
00872 
00873     while (bits)
00874     {
00875         if (bits >= 8)
00876         {
00877             mask = 0xff;
00878             bits -= 8;
00879         }
00880         else
00881         {
00882             mask = 0xff >> (8 - bits);
00883             bits = 0;
00884         }
00885 
00886         b[byte] = mask;
00887         byte--;
00888     }
00889 
00890     ip_family(dst) = ip_family(ip);
00891     ip_bits(dst) = ip_maxbits(ip);
00892     SET_INET_VARSIZE(dst);
00893 
00894     PG_RETURN_INET_P(dst);
00895 }
00896 
00897 /*
00898  * Convert a value of a network datatype to an approximate scalar value.
00899  * This is used for estimating selectivities of inequality operators
00900  * involving network types.
00901  */
00902 double
00903 convert_network_to_scalar(Datum value, Oid typid)
00904 {
00905     switch (typid)
00906     {
00907         case INETOID:
00908         case CIDROID:
00909             {
00910                 inet       *ip = DatumGetInetPP(value);
00911                 int         len;
00912                 double      res;
00913                 int         i;
00914 
00915                 /*
00916                  * Note that we don't use the full address for IPv6.
00917                  */
00918                 if (ip_family(ip) == PGSQL_AF_INET)
00919                     len = 4;
00920                 else
00921                     len = 5;
00922 
00923                 res = ip_family(ip);
00924                 for (i = 0; i < len; i++)
00925                 {
00926                     res *= 256;
00927                     res += ip_addr(ip)[i];
00928                 }
00929                 return res;
00930 
00931                 break;
00932             }
00933         case MACADDROID:
00934             {
00935                 macaddr    *mac = DatumGetMacaddrP(value);
00936                 double      res;
00937 
00938                 res = (mac->a << 16) | (mac->b << 8) | (mac->c);
00939                 res *= 256 * 256 * 256;
00940                 res += (mac->d << 16) | (mac->e << 8) | (mac->f);
00941                 return res;
00942             }
00943     }
00944 
00945     /*
00946      * Can't get here unless someone tries to use scalarltsel/scalargtsel on
00947      * an operator with one network and one non-network operand.
00948      */
00949     elog(ERROR, "unsupported type: %u", typid);
00950     return 0;
00951 }
00952 
00953 /*
00954  * int
00955  * bitncmp(l, r, n)
00956  *      compare bit masks l and r, for n bits.
00957  * return:
00958  *      -1, 1, or 0 in the libc tradition.
00959  * note:
00960  *      network byte order assumed.  this means 192.5.5.240/28 has
00961  *      0x11110000 in its fourth octet.
00962  * author:
00963  *      Paul Vixie (ISC), June 1996
00964  */
00965 static int
00966 bitncmp(void *l, void *r, int n)
00967 {
00968     u_int       lb,
00969                 rb;
00970     int         x,
00971                 b;
00972 
00973     b = n / 8;
00974     x = memcmp(l, r, b);
00975     if (x || (n % 8) == 0)
00976         return x;
00977 
00978     lb = ((const u_char *) l)[b];
00979     rb = ((const u_char *) r)[b];
00980     for (b = n % 8; b > 0; b--)
00981     {
00982         if (IS_HIGHBIT_SET(lb) != IS_HIGHBIT_SET(rb))
00983         {
00984             if (IS_HIGHBIT_SET(lb))
00985                 return 1;
00986             return -1;
00987         }
00988         lb <<= 1;
00989         rb <<= 1;
00990     }
00991     return 0;
00992 }
00993 
00994 static bool
00995 addressOK(unsigned char *a, int bits, int family)
00996 {
00997     int         byte;
00998     int         nbits;
00999     int         maxbits;
01000     int         maxbytes;
01001     unsigned char mask;
01002 
01003     if (family == PGSQL_AF_INET)
01004     {
01005         maxbits = 32;
01006         maxbytes = 4;
01007     }
01008     else
01009     {
01010         maxbits = 128;
01011         maxbytes = 16;
01012     }
01013     Assert(bits <= maxbits);
01014 
01015     if (bits == maxbits)
01016         return true;
01017 
01018     byte = bits / 8;
01019 
01020     nbits = bits % 8;
01021     mask = 0xff;
01022     if (bits != 0)
01023         mask >>= nbits;
01024 
01025     while (byte < maxbytes)
01026     {
01027         if ((a[byte] & mask) != 0)
01028             return false;
01029         mask = 0xff;
01030         byte++;
01031     }
01032 
01033     return true;
01034 }
01035 
01036 
01037 /*
01038  * These functions are used by planner to generate indexscan limits
01039  * for clauses a << b and a <<= b
01040  */
01041 
01042 /* return the minimal value for an IP on a given network */
01043 Datum
01044 network_scan_first(Datum in)
01045 {
01046     return DirectFunctionCall1(network_network, in);
01047 }
01048 
01049 /*
01050  * return "last" IP on a given network. It's the broadcast address,
01051  * however, masklen has to be set to its max btis, since
01052  * 192.168.0.255/24 is considered less than 192.168.0.255/32
01053  *
01054  * inet_set_masklen() hacked to max out the masklength to 128 for IPv6
01055  * and 32 for IPv4 when given '-1' as argument.
01056  */
01057 Datum
01058 network_scan_last(Datum in)
01059 {
01060     return DirectFunctionCall2(inet_set_masklen,
01061                                DirectFunctionCall1(network_broadcast, in),
01062                                Int32GetDatum(-1));
01063 }
01064 
01065 
01066 /*
01067  * IP address that the client is connecting from (NULL if Unix socket)
01068  */
01069 Datum
01070 inet_client_addr(PG_FUNCTION_ARGS)
01071 {
01072     Port       *port = MyProcPort;
01073     char        remote_host[NI_MAXHOST];
01074     int         ret;
01075 
01076     if (port == NULL)
01077         PG_RETURN_NULL();
01078 
01079     switch (port->raddr.addr.ss_family)
01080     {
01081         case AF_INET:
01082 #ifdef HAVE_IPV6
01083         case AF_INET6:
01084 #endif
01085             break;
01086         default:
01087             PG_RETURN_NULL();
01088     }
01089 
01090     remote_host[0] = '\0';
01091 
01092     ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
01093                              remote_host, sizeof(remote_host),
01094                              NULL, 0,
01095                              NI_NUMERICHOST | NI_NUMERICSERV);
01096     if (ret != 0)
01097         PG_RETURN_NULL();
01098 
01099     clean_ipv6_addr(port->raddr.addr.ss_family, remote_host);
01100 
01101     PG_RETURN_INET_P(network_in(remote_host, false));
01102 }
01103 
01104 
01105 /*
01106  * port that the client is connecting from (NULL if Unix socket)
01107  */
01108 Datum
01109 inet_client_port(PG_FUNCTION_ARGS)
01110 {
01111     Port       *port = MyProcPort;
01112     char        remote_port[NI_MAXSERV];
01113     int         ret;
01114 
01115     if (port == NULL)
01116         PG_RETURN_NULL();
01117 
01118     switch (port->raddr.addr.ss_family)
01119     {
01120         case AF_INET:
01121 #ifdef HAVE_IPV6
01122         case AF_INET6:
01123 #endif
01124             break;
01125         default:
01126             PG_RETURN_NULL();
01127     }
01128 
01129     remote_port[0] = '\0';
01130 
01131     ret = pg_getnameinfo_all(&port->raddr.addr, port->raddr.salen,
01132                              NULL, 0,
01133                              remote_port, sizeof(remote_port),
01134                              NI_NUMERICHOST | NI_NUMERICSERV);
01135     if (ret != 0)
01136         PG_RETURN_NULL();
01137 
01138     PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(remote_port)));
01139 }
01140 
01141 
01142 /*
01143  * IP address that the server accepted the connection on (NULL if Unix socket)
01144  */
01145 Datum
01146 inet_server_addr(PG_FUNCTION_ARGS)
01147 {
01148     Port       *port = MyProcPort;
01149     char        local_host[NI_MAXHOST];
01150     int         ret;
01151 
01152     if (port == NULL)
01153         PG_RETURN_NULL();
01154 
01155     switch (port->laddr.addr.ss_family)
01156     {
01157         case AF_INET:
01158 #ifdef HAVE_IPV6
01159         case AF_INET6:
01160 #endif
01161             break;
01162         default:
01163             PG_RETURN_NULL();
01164     }
01165 
01166     local_host[0] = '\0';
01167 
01168     ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen,
01169                              local_host, sizeof(local_host),
01170                              NULL, 0,
01171                              NI_NUMERICHOST | NI_NUMERICSERV);
01172     if (ret != 0)
01173         PG_RETURN_NULL();
01174 
01175     clean_ipv6_addr(port->laddr.addr.ss_family, local_host);
01176 
01177     PG_RETURN_INET_P(network_in(local_host, false));
01178 }
01179 
01180 
01181 /*
01182  * port that the server accepted the connection on (NULL if Unix socket)
01183  */
01184 Datum
01185 inet_server_port(PG_FUNCTION_ARGS)
01186 {
01187     Port       *port = MyProcPort;
01188     char        local_port[NI_MAXSERV];
01189     int         ret;
01190 
01191     if (port == NULL)
01192         PG_RETURN_NULL();
01193 
01194     switch (port->laddr.addr.ss_family)
01195     {
01196         case AF_INET:
01197 #ifdef HAVE_IPV6
01198         case AF_INET6:
01199 #endif
01200             break;
01201         default:
01202             PG_RETURN_NULL();
01203     }
01204 
01205     local_port[0] = '\0';
01206 
01207     ret = pg_getnameinfo_all(&port->laddr.addr, port->laddr.salen,
01208                              NULL, 0,
01209                              local_port, sizeof(local_port),
01210                              NI_NUMERICHOST | NI_NUMERICSERV);
01211     if (ret != 0)
01212         PG_RETURN_NULL();
01213 
01214     PG_RETURN_DATUM(DirectFunctionCall1(int4in, CStringGetDatum(local_port)));
01215 }
01216 
01217 
01218 Datum
01219 inetnot(PG_FUNCTION_ARGS)
01220 {
01221     inet       *ip = PG_GETARG_INET_PP(0);
01222     inet       *dst;
01223 
01224     dst = (inet *) palloc0(sizeof(inet));
01225 
01226     {
01227         int         nb = ip_addrsize(ip);
01228         unsigned char *pip = ip_addr(ip);
01229         unsigned char *pdst = ip_addr(dst);
01230 
01231         while (nb-- > 0)
01232             pdst[nb] = ~pip[nb];
01233     }
01234     ip_bits(dst) = ip_bits(ip);
01235 
01236     ip_family(dst) = ip_family(ip);
01237     SET_INET_VARSIZE(dst);
01238 
01239     PG_RETURN_INET_P(dst);
01240 }
01241 
01242 
01243 Datum
01244 inetand(PG_FUNCTION_ARGS)
01245 {
01246     inet       *ip = PG_GETARG_INET_PP(0);
01247     inet       *ip2 = PG_GETARG_INET_PP(1);
01248     inet       *dst;
01249 
01250     dst = (inet *) palloc0(sizeof(inet));
01251 
01252     if (ip_family(ip) != ip_family(ip2))
01253         ereport(ERROR,
01254                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01255                  errmsg("cannot AND inet values of different sizes")));
01256     else
01257     {
01258         int         nb = ip_addrsize(ip);
01259         unsigned char *pip = ip_addr(ip);
01260         unsigned char *pip2 = ip_addr(ip2);
01261         unsigned char *pdst = ip_addr(dst);
01262 
01263         while (nb-- > 0)
01264             pdst[nb] = pip[nb] & pip2[nb];
01265     }
01266     ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
01267 
01268     ip_family(dst) = ip_family(ip);
01269     SET_INET_VARSIZE(dst);
01270 
01271     PG_RETURN_INET_P(dst);
01272 }
01273 
01274 
01275 Datum
01276 inetor(PG_FUNCTION_ARGS)
01277 {
01278     inet       *ip = PG_GETARG_INET_PP(0);
01279     inet       *ip2 = PG_GETARG_INET_PP(1);
01280     inet       *dst;
01281 
01282     dst = (inet *) palloc0(sizeof(inet));
01283 
01284     if (ip_family(ip) != ip_family(ip2))
01285         ereport(ERROR,
01286                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01287                  errmsg("cannot OR inet values of different sizes")));
01288     else
01289     {
01290         int         nb = ip_addrsize(ip);
01291         unsigned char *pip = ip_addr(ip);
01292         unsigned char *pip2 = ip_addr(ip2);
01293         unsigned char *pdst = ip_addr(dst);
01294 
01295         while (nb-- > 0)
01296             pdst[nb] = pip[nb] | pip2[nb];
01297     }
01298     ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2));
01299 
01300     ip_family(dst) = ip_family(ip);
01301     SET_INET_VARSIZE(dst);
01302 
01303     PG_RETURN_INET_P(dst);
01304 }
01305 
01306 
01307 static inet *
01308 internal_inetpl(inet *ip, int64 addend)
01309 {
01310     inet       *dst;
01311 
01312     dst = (inet *) palloc0(sizeof(inet));
01313 
01314     {
01315         int         nb = ip_addrsize(ip);
01316         unsigned char *pip = ip_addr(ip);
01317         unsigned char *pdst = ip_addr(dst);
01318         int         carry = 0;
01319 
01320         while (nb-- > 0)
01321         {
01322             carry = pip[nb] + (int) (addend & 0xFF) + carry;
01323             pdst[nb] = (unsigned char) (carry & 0xFF);
01324             carry >>= 8;
01325 
01326             /*
01327              * We have to be careful about right-shifting addend because
01328              * right-shift isn't portable for negative values, while simply
01329              * dividing by 256 doesn't work (the standard rounding is in the
01330              * wrong direction, besides which there may be machines out there
01331              * that round the wrong way).  So, explicitly clear the low-order
01332              * byte to remove any doubt about the correct result of the
01333              * division, and then divide rather than shift.
01334              */
01335             addend &= ~((int64) 0xFF);
01336             addend /= 0x100;
01337         }
01338 
01339         /*
01340          * At this point we should have addend and carry both zero if original
01341          * addend was >= 0, or addend -1 and carry 1 if original addend was <
01342          * 0.  Anything else means overflow.
01343          */
01344         if (!((addend == 0 && carry == 0) ||
01345               (addend == -1 && carry == 1)))
01346             ereport(ERROR,
01347                     (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01348                      errmsg("result is out of range")));
01349     }
01350 
01351     ip_bits(dst) = ip_bits(ip);
01352     ip_family(dst) = ip_family(ip);
01353     SET_INET_VARSIZE(dst);
01354 
01355     return dst;
01356 }
01357 
01358 
01359 Datum
01360 inetpl(PG_FUNCTION_ARGS)
01361 {
01362     inet       *ip = PG_GETARG_INET_PP(0);
01363     int64       addend = PG_GETARG_INT64(1);
01364 
01365     PG_RETURN_INET_P(internal_inetpl(ip, addend));
01366 }
01367 
01368 
01369 Datum
01370 inetmi_int8(PG_FUNCTION_ARGS)
01371 {
01372     inet       *ip = PG_GETARG_INET_PP(0);
01373     int64       addend = PG_GETARG_INT64(1);
01374 
01375     PG_RETURN_INET_P(internal_inetpl(ip, -addend));
01376 }
01377 
01378 
01379 Datum
01380 inetmi(PG_FUNCTION_ARGS)
01381 {
01382     inet       *ip = PG_GETARG_INET_PP(0);
01383     inet       *ip2 = PG_GETARG_INET_PP(1);
01384     int64       res = 0;
01385 
01386     if (ip_family(ip) != ip_family(ip2))
01387         ereport(ERROR,
01388                 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
01389                  errmsg("cannot subtract inet values of different sizes")));
01390     else
01391     {
01392         /*
01393          * We form the difference using the traditional complement, increment,
01394          * and add rule, with the increment part being handled by starting the
01395          * carry off at 1.  If you don't think integer arithmetic is done in
01396          * two's complement, too bad.
01397          */
01398         int         nb = ip_addrsize(ip);
01399         int         byte = 0;
01400         unsigned char *pip = ip_addr(ip);
01401         unsigned char *pip2 = ip_addr(ip2);
01402         int         carry = 1;
01403 
01404         while (nb-- > 0)
01405         {
01406             int         lobyte;
01407 
01408             carry = pip[nb] + (~pip2[nb] & 0xFF) + carry;
01409             lobyte = carry & 0xFF;
01410             if (byte < sizeof(int64))
01411             {
01412                 res |= ((int64) lobyte) << (byte * 8);
01413             }
01414             else
01415             {
01416                 /*
01417                  * Input wider than int64: check for overflow.  All bytes to
01418                  * the left of what will fit should be 0 or 0xFF, depending on
01419                  * sign of the now-complete result.
01420                  */
01421                 if ((res < 0) ? (lobyte != 0xFF) : (lobyte != 0))
01422                     ereport(ERROR,
01423                             (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
01424                              errmsg("result is out of range")));
01425             }
01426             carry >>= 8;
01427             byte++;
01428         }
01429 
01430         /*
01431          * If input is narrower than int64, overflow is not possible, but we
01432          * have to do proper sign extension.
01433          */
01434         if (carry == 0 && byte < sizeof(int64))
01435             res |= ((int64) -1) << (byte * 8);
01436     }
01437 
01438     PG_RETURN_INT64(res);
01439 }
01440 
01441 
01442 /*
01443  * clean_ipv6_addr --- remove any '%zone' part from an IPv6 address string
01444  *
01445  * XXX This should go away someday!
01446  *
01447  * This is a kluge needed because we don't yet support zones in stored inet
01448  * values.  Since the result of getnameinfo() might include a zone spec,
01449  * call this to remove it anywhere we want to feed getnameinfo's output to
01450  * network_in.  Beats failing entirely.
01451  *
01452  * An alternative approach would be to let network_in ignore %-parts for
01453  * itself, but that would mean we'd silently drop zone specs in user input,
01454  * which seems not such a good idea.
01455  */
01456 void
01457 clean_ipv6_addr(int addr_family, char *addr)
01458 {
01459 #ifdef HAVE_IPV6
01460     if (addr_family == AF_INET6)
01461     {
01462         char       *pct = strchr(addr, '%');
01463 
01464         if (pct)
01465             *pct = '\0';
01466     }
01467 #endif
01468 }