00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #if defined(LIBC_SCCS) && !defined(lint)
00021 static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.2 2004/03/09 09:17:27 marka Exp $";
00022 #endif
00023
00024 #include "postgres.h"
00025
00026 #include <sys/types.h>
00027 #include <sys/socket.h>
00028 #include <netinet/in.h>
00029 #include <arpa/inet.h>
00030
00031 #include "utils/builtins.h"
00032 #include "utils/inet.h"
00033
00034
00035 #ifdef SPRINTF_CHAR
00036 #define SPRINTF(x) strlen(sprintfx)
00037 #else
00038 #define SPRINTF(x) ((size_t)sprintf x)
00039 #endif
00040
00041 static char *inet_cidr_ntop_ipv4(const u_char *src, int bits,
00042 char *dst, size_t size);
00043 static char *inet_cidr_ntop_ipv6(const u_char *src, int bits,
00044 char *dst, size_t size);
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056 char *
00057 inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size)
00058 {
00059 switch (af)
00060 {
00061 case PGSQL_AF_INET:
00062 return (inet_cidr_ntop_ipv4(src, bits, dst, size));
00063 case PGSQL_AF_INET6:
00064 return (inet_cidr_ntop_ipv6(src, bits, dst, size));
00065 default:
00066 errno = EAFNOSUPPORT;
00067 return (NULL);
00068 }
00069 }
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085 static char *
00086 inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
00087 {
00088 char *odst = dst;
00089 char *t;
00090 u_int m;
00091 int b;
00092
00093 if (bits < 0 || bits > 32)
00094 {
00095 errno = EINVAL;
00096 return (NULL);
00097 }
00098
00099 if (bits == 0)
00100 {
00101 if (size < sizeof "0")
00102 goto emsgsize;
00103 *dst++ = '0';
00104 size--;
00105 *dst = '\0';
00106 }
00107
00108
00109 for (b = bits / 8; b > 0; b--)
00110 {
00111 if (size <= sizeof "255.")
00112 goto emsgsize;
00113 t = dst;
00114 dst += SPRINTF((dst, "%u", *src++));
00115 if (b > 1)
00116 {
00117 *dst++ = '.';
00118 *dst = '\0';
00119 }
00120 size -= (size_t) (dst - t);
00121 }
00122
00123
00124 b = bits % 8;
00125 if (b > 0)
00126 {
00127 if (size <= sizeof ".255")
00128 goto emsgsize;
00129 t = dst;
00130 if (dst != odst)
00131 *dst++ = '.';
00132 m = ((1 << b) - 1) << (8 - b);
00133 dst += SPRINTF((dst, "%u", *src & m));
00134 size -= (size_t) (dst - t);
00135 }
00136
00137
00138 if (size <= sizeof "/32")
00139 goto emsgsize;
00140 dst += SPRINTF((dst, "/%u", bits));
00141 return (odst);
00142
00143 emsgsize:
00144 errno = EMSGSIZE;
00145 return (NULL);
00146 }
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 static char *
00166 inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
00167 {
00168 u_int m;
00169 int b;
00170 int p;
00171 int zero_s,
00172 zero_l,
00173 tmp_zero_s,
00174 tmp_zero_l;
00175 int i;
00176 int is_ipv4 = 0;
00177 unsigned char inbuf[16];
00178 char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
00179 char *cp;
00180 int words;
00181 u_char *s;
00182
00183 if (bits < 0 || bits > 128)
00184 {
00185 errno = EINVAL;
00186 return (NULL);
00187 }
00188
00189 cp = outbuf;
00190
00191 if (bits == 0)
00192 {
00193 *cp++ = ':';
00194 *cp++ = ':';
00195 *cp = '\0';
00196 }
00197 else
00198 {
00199
00200 p = (bits + 7) / 8;
00201 memcpy(inbuf, src, p);
00202 memset(inbuf + p, 0, 16 - p);
00203 b = bits % 8;
00204 if (b != 0)
00205 {
00206 m = ~0 << (8 - b);
00207 inbuf[p - 1] &= m;
00208 }
00209
00210 s = inbuf;
00211
00212
00213 words = (bits + 15) / 16;
00214 if (words == 1)
00215 words = 2;
00216
00217
00218 zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
00219 for (i = 0; i < (words * 2); i += 2)
00220 {
00221 if ((s[i] | s[i + 1]) == 0)
00222 {
00223 if (tmp_zero_l == 0)
00224 tmp_zero_s = i / 2;
00225 tmp_zero_l++;
00226 }
00227 else
00228 {
00229 if (tmp_zero_l && zero_l < tmp_zero_l)
00230 {
00231 zero_s = tmp_zero_s;
00232 zero_l = tmp_zero_l;
00233 tmp_zero_l = 0;
00234 }
00235 }
00236 }
00237
00238 if (tmp_zero_l && zero_l < tmp_zero_l)
00239 {
00240 zero_s = tmp_zero_s;
00241 zero_l = tmp_zero_l;
00242 }
00243
00244 if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
00245 ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
00246 ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
00247 is_ipv4 = 1;
00248
00249
00250 for (p = 0; p < words; p++)
00251 {
00252 if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l)
00253 {
00254
00255 if (p == zero_s)
00256 *cp++ = ':';
00257 if (p == words - 1)
00258 *cp++ = ':';
00259 s++;
00260 s++;
00261 continue;
00262 }
00263
00264 if (is_ipv4 && p > 5)
00265 {
00266 *cp++ = (p == 6) ? ':' : '.';
00267 cp += SPRINTF((cp, "%u", *s++));
00268
00269 if (p != 7 || bits > 120)
00270 {
00271 *cp++ = '.';
00272 cp += SPRINTF((cp, "%u", *s++));
00273 }
00274 }
00275 else
00276 {
00277 if (cp != outbuf)
00278 *cp++ = ':';
00279 cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
00280 s += 2;
00281 }
00282 }
00283 }
00284
00285 (void) SPRINTF((cp, "/%u", bits));
00286 if (strlen(outbuf) + 1 > size)
00287 goto emsgsize;
00288 strcpy(dst, outbuf);
00289
00290 return (dst);
00291
00292 emsgsize:
00293 errno = EMSGSIZE;
00294 return (NULL);
00295 }