libpqtypes - network.c

Home Page

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