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 } |