libpqtypes - network.c

Home Page

array.c
datetime.c
error.c
events.c
exec.c
geo.c
getaddrinfo.h
handler.c
libpqtypes-int.h
libpqtypes.h
misc.c
network.c
numerics.c
param.c
port.c
record.c
regression-test.c
spec.c
utils.c
varlena.c
  1 
  2 /*
  3  * network.c
  4  *   Type handler for the network data types.
  5  *
  6  * Copyright (c) 2011 eSilo, LLC. All rights reserved.
  7  * This is free software; see the source for copying conditions.  There is
  8  * NO warranty; not even for MERCHANTABILITY or  FITNESS FOR A  PARTICULAR
  9  * PURPOSE.
 10  */
 11 
 12 #include "libpqtypes-int.h"
 13 
 14 #if defined(__CYGWIN__) || (defined(HAVE_CONFIG_H) && \
 15   !defined(HAVE_GETADDRINFO))
 16 # include "getaddrinfo.h"
 17 #endif
 18 
 19 #ifndef PGSQL_AF_INET
 20 # define PGSQL_AF_INET  (AF_INET + 0)
 21 #endif
 22 
 23 #ifndef PGSQL_AF_INET6
 24 # define PGSQL_AF_INET6 (AF_INET + 1)
 25 #endif
 26 
 27 #ifndef AF_INET6
 28 #warning NO AF_INET6 SUPPORT!
 29 #endif
 30 
 31 /* Some platforms don't define this, like AIX 4.3 */
 32 #ifndef AI_NUMERICHOST
 33 # define AI_NUMERICHOST 0x04
 34 #endif
 35 
 36 /* handles cidr as well */
 37 int
 38 pqt_put_inet(PGtypeArgs *args)
 39 {
 40   unsigned char *b = (unsigned char *)args->put.out;
 41   PGinet *inet = va_arg(args->ap, PGinet *);
 42   int family;
 43 
 44   PUTNULLCHK(args, inet);
 45 
 46   family = ((struct sockaddr *)inet->sa_buf)->sa_family;
 47 
 48   if (family == AF_INET)
 49   {
 50     struct sockaddr_in *sa = (struct sockaddr_in *) inet->sa_buf;
 51     *b++ = (unsigned char) PGSQL_AF_INET;
 52     *b++ = (unsigned char) inet->mask;
 53     *b++ = (unsigned char) (inet->is_cidr ? 1 : 0);
 54     *b++ = (unsigned char) 4;
 55     memcpy(b, &sa->sin_addr, 4);
 56     b += 4;
 57   }
 58 #ifdef AF_INET6
 59   else if (family == AF_INET6)
 60   {
 61     struct sockaddr_in6 *sa = (struct sockaddr_in6 *) inet->sa_buf;
 62     *b++ = (unsigned char) PGSQL_AF_INET6;
 63     *b++ = (unsigned char) inet->mask;
 64     *b++ = (unsigned char) (inet->is_cidr ? 1 : 0);
 65     *b++ = (unsigned char) 16;
 66     memcpy(b, &sa->sin6_addr, 16);
 67     b += 16;
 68   }
 69 #endif
 70   else
 71   {
 72     return args->errorf(args, "Unknown inet address family %d", family);
 73   }
 74 
 75   return (int) ((char *) b - args->put.out);
 76 }
 77 
 78 static int
 79 get_inet2(PGtypeArgs *args, int is_cidr)
 80 {
 81   DECLVALUE(args);
 82   unsigned short family;
 83   PGinet *inet = va_arg(args->ap, PGinet *);
 84 
 85   CHKGETVALS(args, inet);
 86 
 87   if (args->format == TEXTFMT)
 88   {
 89     int r;
 90     char *p;
 91     char ipstr[80];
 92     struct addrinfo *ai = NULL;
 93     struct addrinfo hints;
 94 
 95     pqt_strcpy(ipstr, sizeof(ipstr), value);
 96     if ((p = strrchr(ipstr, '/')))
 97     {
 98       *p = 0;
 99       inet->mask = atoi(p+1);
100     }
101     else
102     {
103       inet->mask = 32;
104     }
105 
106     inet->is_cidr = is_cidr;
107 
108     /* suppress hostname lookups */
109     memset(&hints, 0, sizeof(hints));
110     hints.ai_flags = AI_NUMERICHOST;
111 
112     /* Without this, windows chokes with WSAHOST_NOT_FOUND */
113 #ifdef PQT_WIN32
114     hints.ai_family = AF_INET;
115 #endif
116 
117     if ((r = getaddrinfo(ipstr, NULL, &hints, &ai)) || !ai)
118     {
119       if(r == EAI_BADFLAGS)
120       {
121         hints.ai_flags = 0;
122         r = getaddrinfo(ipstr, NULL, &hints, &ai);
123       }
124       /* Another WSAHOST_NOT_FOUND work around, but for IPv6 */
125 #if defined(PQT_WIN32) && defined(AF_INET6)
126       else if(r == WSAHOST_NOT_FOUND)
127       {
128         hints.ai_flags = 0;
129         hints.ai_family = AF_INET6;
130         r = getaddrinfo(ipstr, NULL, &hints, &ai);
131       }
132 #endif
133 
134       if(r)
135         RERR_STR2INT(args);
136     }
137 
138     inet->sa_buf_len = (int) ai->ai_addrlen;
139     memcpy(inet->sa_buf, ai->ai_addr, inet->sa_buf_len);
140 
141     /* Some platforms, lika AIX 4.3, do not zero this structure properly.
142      * The family and port are dirty, so set the first 4 bytes to 0 and
143      * then re-set the family.  I saw "0x1002" as the first 2 bytes of
144      * this structure (dumb getaddrinfo), it should be "0x0002" for AF_INET.
145      */
146     memset(inet->sa_buf, 0, 4);
147     ((struct sockaddr *)inet->sa_buf)->sa_family = ai->ai_addr->sa_family;
148 
149     /* Uninitialized memory, postgres inet/cidr types don't store this.
150      * Make sure its set to 0.  Another AIX problem (maybe other platforms).
151      */
152 #ifdef AF_INET6
153     if (ai->ai_addr->sa_family == AF_INET6)
154       ((struct sockaddr_in6 *)inet->sa_buf)->sin6_flowinfo = 0;
155 #endif
156 
157     freeaddrinfo(ai);
158     return 0;
159   }
160 
161   family = (unsigned short) *value++;
162   if (family == PGSQL_AF_INET)
163   {
164     struct sockaddr_in *sa = (struct sockaddr_in *) inet->sa_buf;
165     sa->sin_family = AF_INET;
166     inet->mask = (unsigned char) *value++;
167     inet->is_cidr = *value++;
168     memcpy(&sa->sin_addr, value + 1, *value);
169     inet->sa_buf_len = (int) sizeof(struct sockaddr_in);
170   }
171 #ifdef AF_INET6
172   else if (family == PGSQL_AF_INET6)
173   {
174     struct sockaddr_in6 *sa = (struct sockaddr_in6 *) inet->sa_buf;
175     sa->sin6_family = AF_INET6;
176     inet->mask = (unsigned char) *value++;
177     inet->is_cidr = *value++;
178     memcpy(&sa->sin6_addr, value + 1, *value);
179     inet->sa_buf_len = (int) sizeof(struct sockaddr_in6);
180   }
181 #endif
182   else
183   {
184     return args->errorf(args, "Unknown inet address family %d", family);
185   }
186 
187   return 0;
188 }
189 
190 int
191 pqt_get_inet(PGtypeArgs *args)
192 {
193   return get_inet2(args, 0);
194 }
195 
196 int
197 pqt_get_cidr(PGtypeArgs *args)
198 {
199   return get_inet2(args, 1);
200 }
201 
202 int
203 pqt_put_macaddr(PGtypeArgs *args)
204 {
205   PGmacaddr *mac = va_arg(args->ap, PGmacaddr *);
206 
207   PUTNULLCHK(args, mac);
208 
209   args->put.out[0] = (unsigned char) mac->a;
210   args->put.out[1] = (unsigned char) mac->b;
211   args->put.out[2] = (unsigned char) mac->c;
212   args->put.out[3] = (unsigned char) mac->d;
213   args->put.out[4] = (unsigned char) mac->e;
214   args->put.out[5] = (unsigned char) mac->f;
215   return 6;
216 }
217 
218 int
219 pqt_get_macaddr(PGtypeArgs *args)
220 {
221   DECLVALUE(args);
222   unsigned char *p;
223   PGmacaddr *mac = va_arg(args->ap, PGmacaddr *);
224 
225   CHKGETVALS(args, mac);
226 
227   if (args->format == TEXTFMT)
228   {
229     int a,b,c,d,e,f;
230     int count = sscanf(value, "%x:%x:%x:%x:%x:%x", &a,&b,&c,&d,&e,&f);
231 
232     if (count != 6 || (a < 0) || (a > 255) || (b < 0) || (b > 255) ||
233         (c < 0) || (c > 255) || (d < 0) || (d > 255) ||
234         (e < 0) || (e > 255) || (f < 0) || (f > 255))
235       RERR_STR2INT(args);
236 
237     mac->a = a;
238     mac->b = b;
239     mac->c = c;
240     mac->d = d;
241     mac->e = e;
242     mac->f = f;
243     return 0;
244   }
245 
246   p = (unsigned char *) value;
247   mac->a = *p++;
248   mac->b = *p++;
249   mac->c = *p++;
250   mac->d = *p++;
251   mac->e = *p++;
252   mac->f = *p;
253   return 0;
254 }