1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * ifaddr.c |
4 | * IP netmask calculations, and enumerating network interfaces. |
5 | * |
6 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
7 | * Portions Copyright (c) 1994, Regents of the University of California |
8 | * |
9 | * |
10 | * IDENTIFICATION |
11 | * src/backend/libpq/ifaddr.c |
12 | * |
13 | * This file and the IPV6 implementation were initially provided by |
14 | * Nigel Kukard <nkukard@lbsd.net>, Linux Based Systems Design |
15 | * http://www.lbsd.net. |
16 | * |
17 | *------------------------------------------------------------------------- |
18 | */ |
19 | |
20 | #include "postgres.h" |
21 | |
22 | #include <unistd.h> |
23 | #include <sys/stat.h> |
24 | #include <sys/socket.h> |
25 | #include <netdb.h> |
26 | #include <netinet/in.h> |
27 | #ifdef HAVE_NETINET_TCP_H |
28 | #include <netinet/tcp.h> |
29 | #endif |
30 | #include <sys/file.h> |
31 | |
32 | #include "libpq/ifaddr.h" |
33 | #include "port/pg_bswap.h" |
34 | |
35 | static int range_sockaddr_AF_INET(const struct sockaddr_in *addr, |
36 | const struct sockaddr_in *netaddr, |
37 | const struct sockaddr_in *netmask); |
38 | |
39 | #ifdef HAVE_IPV6 |
40 | static int range_sockaddr_AF_INET6(const struct sockaddr_in6 *addr, |
41 | const struct sockaddr_in6 *netaddr, |
42 | const struct sockaddr_in6 *netmask); |
43 | #endif |
44 | |
45 | |
46 | /* |
47 | * pg_range_sockaddr - is addr within the subnet specified by netaddr/netmask ? |
48 | * |
49 | * Note: caller must already have verified that all three addresses are |
50 | * in the same address family; and AF_UNIX addresses are not supported. |
51 | */ |
52 | int |
53 | pg_range_sockaddr(const struct sockaddr_storage *addr, |
54 | const struct sockaddr_storage *netaddr, |
55 | const struct sockaddr_storage *netmask) |
56 | { |
57 | if (addr->ss_family == AF_INET) |
58 | return range_sockaddr_AF_INET((const struct sockaddr_in *) addr, |
59 | (const struct sockaddr_in *) netaddr, |
60 | (const struct sockaddr_in *) netmask); |
61 | #ifdef HAVE_IPV6 |
62 | else if (addr->ss_family == AF_INET6) |
63 | return range_sockaddr_AF_INET6((const struct sockaddr_in6 *) addr, |
64 | (const struct sockaddr_in6 *) netaddr, |
65 | (const struct sockaddr_in6 *) netmask); |
66 | #endif |
67 | else |
68 | return 0; |
69 | } |
70 | |
71 | static int |
72 | range_sockaddr_AF_INET(const struct sockaddr_in *addr, |
73 | const struct sockaddr_in *netaddr, |
74 | const struct sockaddr_in *netmask) |
75 | { |
76 | if (((addr->sin_addr.s_addr ^ netaddr->sin_addr.s_addr) & |
77 | netmask->sin_addr.s_addr) == 0) |
78 | return 1; |
79 | else |
80 | return 0; |
81 | } |
82 | |
83 | |
84 | #ifdef HAVE_IPV6 |
85 | |
86 | static int |
87 | range_sockaddr_AF_INET6(const struct sockaddr_in6 *addr, |
88 | const struct sockaddr_in6 *netaddr, |
89 | const struct sockaddr_in6 *netmask) |
90 | { |
91 | int i; |
92 | |
93 | for (i = 0; i < 16; i++) |
94 | { |
95 | if (((addr->sin6_addr.s6_addr[i] ^ netaddr->sin6_addr.s6_addr[i]) & |
96 | netmask->sin6_addr.s6_addr[i]) != 0) |
97 | return 0; |
98 | } |
99 | |
100 | return 1; |
101 | } |
102 | #endif /* HAVE_IPV6 */ |
103 | |
104 | /* |
105 | * pg_sockaddr_cidr_mask - make a network mask of the appropriate family |
106 | * and required number of significant bits |
107 | * |
108 | * numbits can be null, in which case the mask is fully set. |
109 | * |
110 | * The resulting mask is placed in *mask, which had better be big enough. |
111 | * |
112 | * Return value is 0 if okay, -1 if not. |
113 | */ |
114 | int |
115 | pg_sockaddr_cidr_mask(struct sockaddr_storage *mask, char *numbits, int family) |
116 | { |
117 | long bits; |
118 | char *endptr; |
119 | |
120 | if (numbits == NULL) |
121 | { |
122 | bits = (family == AF_INET) ? 32 : 128; |
123 | } |
124 | else |
125 | { |
126 | bits = strtol(numbits, &endptr, 10); |
127 | if (*numbits == '\0' || *endptr != '\0') |
128 | return -1; |
129 | } |
130 | |
131 | switch (family) |
132 | { |
133 | case AF_INET: |
134 | { |
135 | struct sockaddr_in mask4; |
136 | long maskl; |
137 | |
138 | if (bits < 0 || bits > 32) |
139 | return -1; |
140 | memset(&mask4, 0, sizeof(mask4)); |
141 | /* avoid "x << 32", which is not portable */ |
142 | if (bits > 0) |
143 | maskl = (0xffffffffUL << (32 - (int) bits)) |
144 | & 0xffffffffUL; |
145 | else |
146 | maskl = 0; |
147 | mask4.sin_addr.s_addr = pg_hton32(maskl); |
148 | memcpy(mask, &mask4, sizeof(mask4)); |
149 | break; |
150 | } |
151 | |
152 | #ifdef HAVE_IPV6 |
153 | case AF_INET6: |
154 | { |
155 | struct sockaddr_in6 mask6; |
156 | int i; |
157 | |
158 | if (bits < 0 || bits > 128) |
159 | return -1; |
160 | memset(&mask6, 0, sizeof(mask6)); |
161 | for (i = 0; i < 16; i++) |
162 | { |
163 | if (bits <= 0) |
164 | mask6.sin6_addr.s6_addr[i] = 0; |
165 | else if (bits >= 8) |
166 | mask6.sin6_addr.s6_addr[i] = 0xff; |
167 | else |
168 | { |
169 | mask6.sin6_addr.s6_addr[i] = |
170 | (0xff << (8 - (int) bits)) & 0xff; |
171 | } |
172 | bits -= 8; |
173 | } |
174 | memcpy(mask, &mask6, sizeof(mask6)); |
175 | break; |
176 | } |
177 | #endif |
178 | default: |
179 | return -1; |
180 | } |
181 | |
182 | mask->ss_family = family; |
183 | return 0; |
184 | } |
185 | |
186 | |
187 | /* |
188 | * Run the callback function for the addr/mask, after making sure the |
189 | * mask is sane for the addr. |
190 | */ |
191 | static void |
192 | run_ifaddr_callback(PgIfAddrCallback callback, void *cb_data, |
193 | struct sockaddr *addr, struct sockaddr *mask) |
194 | { |
195 | struct sockaddr_storage fullmask; |
196 | |
197 | if (!addr) |
198 | return; |
199 | |
200 | /* Check that the mask is valid */ |
201 | if (mask) |
202 | { |
203 | if (mask->sa_family != addr->sa_family) |
204 | { |
205 | mask = NULL; |
206 | } |
207 | else if (mask->sa_family == AF_INET) |
208 | { |
209 | if (((struct sockaddr_in *) mask)->sin_addr.s_addr == INADDR_ANY) |
210 | mask = NULL; |
211 | } |
212 | #ifdef HAVE_IPV6 |
213 | else if (mask->sa_family == AF_INET6) |
214 | { |
215 | if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *) mask)->sin6_addr)) |
216 | mask = NULL; |
217 | } |
218 | #endif |
219 | } |
220 | |
221 | /* If mask is invalid, generate our own fully-set mask */ |
222 | if (!mask) |
223 | { |
224 | pg_sockaddr_cidr_mask(&fullmask, NULL, addr->sa_family); |
225 | mask = (struct sockaddr *) &fullmask; |
226 | } |
227 | |
228 | (*callback) (addr, mask, cb_data); |
229 | } |
230 | |
231 | #ifdef WIN32 |
232 | |
233 | #include <winsock2.h> |
234 | #include <ws2tcpip.h> |
235 | |
236 | /* |
237 | * Enumerate the system's network interface addresses and call the callback |
238 | * for each one. Returns 0 if successful, -1 if trouble. |
239 | * |
240 | * This version is for Win32. Uses the Winsock 2 functions (ie: ws2_32.dll) |
241 | */ |
242 | int |
243 | pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) |
244 | { |
245 | INTERFACE_INFO *ptr, |
246 | *ii = NULL; |
247 | unsigned long length, |
248 | i; |
249 | unsigned long n_ii = 0; |
250 | SOCKET sock; |
251 | int error; |
252 | |
253 | sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); |
254 | if (sock == INVALID_SOCKET) |
255 | return -1; |
256 | |
257 | while (n_ii < 1024) |
258 | { |
259 | n_ii += 64; |
260 | ptr = realloc(ii, sizeof(INTERFACE_INFO) * n_ii); |
261 | if (!ptr) |
262 | { |
263 | free(ii); |
264 | closesocket(sock); |
265 | errno = ENOMEM; |
266 | return -1; |
267 | } |
268 | |
269 | ii = ptr; |
270 | if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, |
271 | ii, n_ii * sizeof(INTERFACE_INFO), |
272 | &length, 0, 0) == SOCKET_ERROR) |
273 | { |
274 | error = WSAGetLastError(); |
275 | if (error == WSAEFAULT || error == WSAENOBUFS) |
276 | continue; /* need to make the buffer bigger */ |
277 | closesocket(sock); |
278 | free(ii); |
279 | return -1; |
280 | } |
281 | |
282 | break; |
283 | } |
284 | |
285 | for (i = 0; i < length / sizeof(INTERFACE_INFO); ++i) |
286 | run_ifaddr_callback(callback, cb_data, |
287 | (struct sockaddr *) &ii[i].iiAddress, |
288 | (struct sockaddr *) &ii[i].iiNetmask); |
289 | |
290 | closesocket(sock); |
291 | free(ii); |
292 | return 0; |
293 | } |
294 | #elif HAVE_GETIFADDRS /* && !WIN32 */ |
295 | |
296 | #ifdef HAVE_IFADDRS_H |
297 | #include <ifaddrs.h> |
298 | #endif |
299 | |
300 | /* |
301 | * Enumerate the system's network interface addresses and call the callback |
302 | * for each one. Returns 0 if successful, -1 if trouble. |
303 | * |
304 | * This version uses the getifaddrs() interface, which is available on |
305 | * BSDs, AIX, and modern Linux. |
306 | */ |
307 | int |
308 | pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) |
309 | { |
310 | struct ifaddrs *ifa, |
311 | *l; |
312 | |
313 | if (getifaddrs(&ifa) < 0) |
314 | return -1; |
315 | |
316 | for (l = ifa; l; l = l->ifa_next) |
317 | run_ifaddr_callback(callback, cb_data, |
318 | l->ifa_addr, l->ifa_netmask); |
319 | |
320 | freeifaddrs(ifa); |
321 | return 0; |
322 | } |
323 | #else /* !HAVE_GETIFADDRS && !WIN32 */ |
324 | |
325 | #include <sys/ioctl.h> |
326 | |
327 | #ifdef HAVE_NET_IF_H |
328 | #include <net/if.h> |
329 | #endif |
330 | |
331 | #ifdef HAVE_SYS_SOCKIO_H |
332 | #include <sys/sockio.h> |
333 | #endif |
334 | |
335 | /* |
336 | * SIOCGIFCONF does not return IPv6 addresses on Solaris |
337 | * and HP/UX. So we prefer SIOCGLIFCONF if it's available. |
338 | * |
339 | * On HP/UX, however, it *only* returns IPv6 addresses, |
340 | * and the structs are named slightly differently too. |
341 | * We'd have to do another call with SIOCGIFCONF to get the |
342 | * IPv4 addresses as well. We don't currently bother, just |
343 | * fall back to SIOCGIFCONF on HP/UX. |
344 | */ |
345 | |
346 | #if defined(SIOCGLIFCONF) && !defined(__hpux) |
347 | |
348 | /* |
349 | * Enumerate the system's network interface addresses and call the callback |
350 | * for each one. Returns 0 if successful, -1 if trouble. |
351 | * |
352 | * This version uses ioctl(SIOCGLIFCONF). |
353 | */ |
354 | int |
355 | pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) |
356 | { |
357 | struct lifconf lifc; |
358 | struct lifreq *lifr, |
359 | lmask; |
360 | struct sockaddr *addr, |
361 | *mask; |
362 | char *ptr, |
363 | *buffer = NULL; |
364 | size_t n_buffer = 1024; |
365 | pgsocket sock, |
366 | fd; |
367 | |
368 | #ifdef HAVE_IPV6 |
369 | pgsocket sock6; |
370 | #endif |
371 | int i, |
372 | total; |
373 | |
374 | sock = socket(AF_INET, SOCK_DGRAM, 0); |
375 | if (sock == PGINVALID_SOCKET) |
376 | return -1; |
377 | |
378 | while (n_buffer < 1024 * 100) |
379 | { |
380 | n_buffer += 1024; |
381 | ptr = realloc(buffer, n_buffer); |
382 | if (!ptr) |
383 | { |
384 | free(buffer); |
385 | close(sock); |
386 | errno = ENOMEM; |
387 | return -1; |
388 | } |
389 | |
390 | memset(&lifc, 0, sizeof(lifc)); |
391 | lifc.lifc_family = AF_UNSPEC; |
392 | lifc.lifc_buf = buffer = ptr; |
393 | lifc.lifc_len = n_buffer; |
394 | |
395 | if (ioctl(sock, SIOCGLIFCONF, &lifc) < 0) |
396 | { |
397 | if (errno == EINVAL) |
398 | continue; |
399 | free(buffer); |
400 | close(sock); |
401 | return -1; |
402 | } |
403 | |
404 | /* |
405 | * Some Unixes try to return as much data as possible, with no |
406 | * indication of whether enough space allocated. Don't believe we have |
407 | * it all unless there's lots of slop. |
408 | */ |
409 | if (lifc.lifc_len < n_buffer - 1024) |
410 | break; |
411 | } |
412 | |
413 | #ifdef HAVE_IPV6 |
414 | /* We'll need an IPv6 socket too for the SIOCGLIFNETMASK ioctls */ |
415 | sock6 = socket(AF_INET6, SOCK_DGRAM, 0); |
416 | if (sock6 == PGINVALID_SOCKET) |
417 | { |
418 | free(buffer); |
419 | close(sock); |
420 | return -1; |
421 | } |
422 | #endif |
423 | |
424 | total = lifc.lifc_len / sizeof(struct lifreq); |
425 | lifr = lifc.lifc_req; |
426 | for (i = 0; i < total; ++i) |
427 | { |
428 | addr = (struct sockaddr *) &lifr[i].lifr_addr; |
429 | memcpy(&lmask, &lifr[i], sizeof(struct lifreq)); |
430 | #ifdef HAVE_IPV6 |
431 | fd = (addr->sa_family == AF_INET6) ? sock6 : sock; |
432 | #else |
433 | fd = sock; |
434 | #endif |
435 | if (ioctl(fd, SIOCGLIFNETMASK, &lmask) < 0) |
436 | mask = NULL; |
437 | else |
438 | mask = (struct sockaddr *) &lmask.lifr_addr; |
439 | run_ifaddr_callback(callback, cb_data, addr, mask); |
440 | } |
441 | |
442 | free(buffer); |
443 | close(sock); |
444 | #ifdef HAVE_IPV6 |
445 | close(sock6); |
446 | #endif |
447 | return 0; |
448 | } |
449 | #elif defined(SIOCGIFCONF) |
450 | |
451 | /* |
452 | * Remaining Unixes use SIOCGIFCONF. Some only return IPv4 information |
453 | * here, so this is the least preferred method. Note that there is no |
454 | * standard way to iterate the struct ifreq returned in the array. |
455 | * On some OSs the structures are padded large enough for any address, |
456 | * on others you have to calculate the size of the struct ifreq. |
457 | */ |
458 | |
459 | /* Some OSs have _SIZEOF_ADDR_IFREQ, so just use that */ |
460 | #ifndef _SIZEOF_ADDR_IFREQ |
461 | |
462 | /* Calculate based on sockaddr.sa_len */ |
463 | #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN |
464 | #define _SIZEOF_ADDR_IFREQ(ifr) \ |
465 | ((ifr).ifr_addr.sa_len > sizeof(struct sockaddr) ? \ |
466 | (sizeof(struct ifreq) - sizeof(struct sockaddr) + \ |
467 | (ifr).ifr_addr.sa_len) : sizeof(struct ifreq)) |
468 | |
469 | /* Padded ifreq structure, simple */ |
470 | #else |
471 | #define _SIZEOF_ADDR_IFREQ(ifr) \ |
472 | sizeof (struct ifreq) |
473 | #endif |
474 | #endif /* !_SIZEOF_ADDR_IFREQ */ |
475 | |
476 | /* |
477 | * Enumerate the system's network interface addresses and call the callback |
478 | * for each one. Returns 0 if successful, -1 if trouble. |
479 | * |
480 | * This version uses ioctl(SIOCGIFCONF). |
481 | */ |
482 | int |
483 | pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) |
484 | { |
485 | struct ifconf ifc; |
486 | struct ifreq *ifr, |
487 | *end, |
488 | addr, |
489 | mask; |
490 | char *ptr, |
491 | *buffer = NULL; |
492 | size_t n_buffer = 1024; |
493 | pgsocket sock; |
494 | |
495 | sock = socket(AF_INET, SOCK_DGRAM, 0); |
496 | if (sock == PGINVALID_SOCKET) |
497 | return -1; |
498 | |
499 | while (n_buffer < 1024 * 100) |
500 | { |
501 | n_buffer += 1024; |
502 | ptr = realloc(buffer, n_buffer); |
503 | if (!ptr) |
504 | { |
505 | free(buffer); |
506 | close(sock); |
507 | errno = ENOMEM; |
508 | return -1; |
509 | } |
510 | |
511 | memset(&ifc, 0, sizeof(ifc)); |
512 | ifc.ifc_buf = buffer = ptr; |
513 | ifc.ifc_len = n_buffer; |
514 | |
515 | if (ioctl(sock, SIOCGIFCONF, &ifc) < 0) |
516 | { |
517 | if (errno == EINVAL) |
518 | continue; |
519 | free(buffer); |
520 | close(sock); |
521 | return -1; |
522 | } |
523 | |
524 | /* |
525 | * Some Unixes try to return as much data as possible, with no |
526 | * indication of whether enough space allocated. Don't believe we have |
527 | * it all unless there's lots of slop. |
528 | */ |
529 | if (ifc.ifc_len < n_buffer - 1024) |
530 | break; |
531 | } |
532 | |
533 | end = (struct ifreq *) (buffer + ifc.ifc_len); |
534 | for (ifr = ifc.ifc_req; ifr < end;) |
535 | { |
536 | memcpy(&addr, ifr, sizeof(addr)); |
537 | memcpy(&mask, ifr, sizeof(mask)); |
538 | if (ioctl(sock, SIOCGIFADDR, &addr, sizeof(addr)) == 0 && |
539 | ioctl(sock, SIOCGIFNETMASK, &mask, sizeof(mask)) == 0) |
540 | run_ifaddr_callback(callback, cb_data, |
541 | &addr.ifr_addr, &mask.ifr_addr); |
542 | ifr = (struct ifreq *) ((char *) ifr + _SIZEOF_ADDR_IFREQ(*ifr)); |
543 | } |
544 | |
545 | free(buffer); |
546 | close(sock); |
547 | return 0; |
548 | } |
549 | #else /* !defined(SIOCGIFCONF) */ |
550 | |
551 | /* |
552 | * Enumerate the system's network interface addresses and call the callback |
553 | * for each one. Returns 0 if successful, -1 if trouble. |
554 | * |
555 | * This version is our fallback if there's no known way to get the |
556 | * interface addresses. Just return the standard loopback addresses. |
557 | */ |
558 | int |
559 | pg_foreach_ifaddr(PgIfAddrCallback callback, void *cb_data) |
560 | { |
561 | struct sockaddr_in addr; |
562 | struct sockaddr_storage mask; |
563 | |
564 | #ifdef HAVE_IPV6 |
565 | struct sockaddr_in6 addr6; |
566 | #endif |
567 | |
568 | /* addr 127.0.0.1/8 */ |
569 | memset(&addr, 0, sizeof(addr)); |
570 | addr.sin_family = AF_INET; |
571 | addr.sin_addr.s_addr = pg_ntoh32(0x7f000001); |
572 | memset(&mask, 0, sizeof(mask)); |
573 | pg_sockaddr_cidr_mask(&mask, "8" , AF_INET); |
574 | run_ifaddr_callback(callback, cb_data, |
575 | (struct sockaddr *) &addr, |
576 | (struct sockaddr *) &mask); |
577 | |
578 | #ifdef HAVE_IPV6 |
579 | /* addr ::1/128 */ |
580 | memset(&addr6, 0, sizeof(addr6)); |
581 | addr6.sin6_family = AF_INET6; |
582 | addr6.sin6_addr.s6_addr[15] = 1; |
583 | memset(&mask, 0, sizeof(mask)); |
584 | pg_sockaddr_cidr_mask(&mask, "128" , AF_INET6); |
585 | run_ifaddr_callback(callback, cb_data, |
586 | (struct sockaddr *) &addr6, |
587 | (struct sockaddr *) &mask); |
588 | #endif |
589 | |
590 | return 0; |
591 | } |
592 | #endif /* !defined(SIOCGIFCONF) */ |
593 | |
594 | #endif /* !HAVE_GETIFADDRS */ |
595 | |