1 /*
2 * uhub - A tiny ADC p2p connection hub
3 * Copyright (C) 2007-2014, Jan Vidar Krey
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #include "uhub.h"
21
22 static int is_ipv6_supported = -1; /* -1 = CHECK, 0 = NO, 1 = YES */
23 static int net_initialized = 0;
24
25 static struct net_statistics stats;
26 static struct net_statistics stats_total;
27
28 #if defined(IPV6_BINDV6ONLY)
29 #define SOCK_DUAL_STACK_OPT IPV6_BINDV6ONLY
30 #elif defined(IPV6_V6ONLY)
31 #define SOCK_DUAL_STACK_OPT IPV6_V6ONLY
32 #endif
33
34
net_initialize()35 int net_initialize()
36 {
37 #ifdef WINSOCK
38 struct WSAData wsa;
39 #endif
40 if (!net_initialized)
41 {
42 LOG_TRACE("Initializing network monitor.");
43
44 #ifdef WINSOCK
45 if (WSAStartup(MAKEWORD(2, 2), &wsa) != NO_ERROR)
46 {
47 LOG_ERROR("Unable to initialize winsock.");
48 return -1;
49 }
50 #endif /* WINSOCK */
51
52 if (!net_backend_init()
53 #ifdef SSL_SUPPORT
54 || !net_ssl_library_init()
55 #endif
56 )
57 {
58 #ifdef WINSOCK
59 WSACleanup();
60 #endif
61 return -1;
62 }
63
64 net_dns_initialize();
65
66 net_stats_initialize();
67 net_initialized = 1;
68 return 0;
69 }
70 return -1;
71 }
72
net_get_max_sockets()73 size_t net_get_max_sockets()
74 {
75 #ifdef HAVE_GETRLIMIT
76 struct rlimit limits;
77 if (getrlimit(RLIMIT_NOFILE, &limits) == 0)
78 {
79 return MIN(limits.rlim_max, 65536);
80 }
81 LOG_ERROR("getrlimit() failed");
82 return 1024;
83 #else
84 #ifdef WIN32
85 return FD_SETSIZE;
86 #else
87 LOG_WARN("System does not have getrlimit(): constrained to 1024 sockets");
88 return 1024;
89 #endif
90 #endif /* HAVE_GETRLIMIT */
91 }
92
93
net_destroy()94 int net_destroy()
95 {
96 if (net_initialized)
97 {
98 LOG_TRACE("Shutting down network monitor");
99
100 net_dns_destroy();
101
102 net_backend_shutdown();
103
104 #ifdef SSL_SUPPORT
105 net_ssl_library_shutdown();
106 #endif /* SSL_SUPPORT */
107
108 #ifdef WINSOCK
109 WSACleanup();
110 #endif
111 net_initialized = 0;
112 return 0;
113 }
114 return -1;
115 }
116
net_error_out(int fd,const char * func)117 static void net_error_out(int fd, const char* func)
118 {
119 int err = net_error();
120 LOG_ERROR("%s, fd=%d: %s (%d)", func, fd, net_error_string(err), err);
121 }
122
net_error()123 int net_error()
124 {
125 #ifdef WINSOCK
126 return WSAGetLastError();
127 #else
128 return errno;
129 #endif
130 }
131
132
net_error_string(int code)133 const char* net_error_string(int code)
134 {
135 #ifdef WINSOCK
136 static char string[32];
137 snprintf(string, 32, "error code: %d", code);
138 return string;
139 #else
140 return strerror(code);
141 #endif
142 }
143
144
net_setsockopt(int fd,int level,int opt,const void * optval,socklen_t optlen)145 static int net_setsockopt(int fd, int level, int opt, const void* optval, socklen_t optlen)
146 {
147 int ret = -1;
148 #ifdef WINSOCK
149 ret = setsockopt(fd, level, opt, (const char*) optval, optlen);
150 #else
151 ret = setsockopt(fd, level, opt, optval, optlen);
152 #endif
153
154 if (ret == -1)
155 {
156 net_error_out(fd, "net_setsockopt");
157 }
158
159 return ret;
160 }
161
net_getsockopt(int fd,int level,int opt,void * optval,socklen_t * optlen)162 static int net_getsockopt(int fd, int level, int opt, void* optval, socklen_t* optlen)
163 {
164 int ret = -1;
165 #ifdef WINSOCK
166 ret = getsockopt(fd, level, opt, (char*) optval, optlen);
167 #else
168 ret = getsockopt(fd, level, opt, optval, optlen);
169 #endif
170
171 if (ret == -1)
172 {
173 net_error_out(fd, "net_getsockopt");
174 }
175
176 return ret;
177 }
178
179
net_set_nonblocking(int fd,int toggle)180 int net_set_nonblocking(int fd, int toggle)
181 {
182 int ret = -1;
183 #ifdef WINSOCK
184 u_long on = toggle ? 1 : 0;
185 ret = ioctlsocket(fd, FIONBIO, &on);
186 #else
187 #ifdef __sun__
188 int flags = fcntl(fd, F_GETFL, 0);
189 if (flags != -1)
190 {
191 if (toggle) flags |= O_NONBLOCK;
192 else flags &= ~O_NONBLOCK;
193 ret = fcntl(fd, F_SETFL, flags);
194 }
195 #else
196 ret = ioctl(fd, FIONBIO, &toggle);
197 #endif
198 #endif
199 if (ret == -1)
200 {
201 net_error_out(fd, "net_set_nonblocking");
202 }
203 return ret;
204 }
205
206 /* NOTE: Possibly only supported on BSD and OSX? */
net_set_nosigpipe(int fd,int toggle)207 int net_set_nosigpipe(int fd, int toggle)
208 {
209 int ret = -1;
210 #ifdef SO_NOSIGPIPE
211 ret = net_setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &toggle, sizeof(toggle));
212 if (ret == -1)
213 {
214 net_error_out(fd, "net_set_nosigpipe");
215 }
216 #endif
217 return ret;
218 }
219
net_set_close_on_exec(int fd,int toggle)220 int net_set_close_on_exec(int fd, int toggle)
221 {
222 #ifdef WINSOCK
223 return -1; /* FIXME: How is this done on Windows? */
224 #else
225 return fcntl(fd, F_SETFD, toggle);
226 #endif
227 }
228
net_set_linger(int fd,int toggle)229 int net_set_linger(int fd, int toggle)
230 {
231 int ret;
232 ret = net_setsockopt(fd, SOL_SOCKET, SO_LINGER, &toggle, sizeof(toggle));
233 if (ret == -1)
234 {
235 net_error_out(fd, "net_set_linger");
236 }
237 return ret;
238 }
239
net_set_keepalive(int fd,int toggle)240 int net_set_keepalive(int fd, int toggle)
241 {
242 int ret;
243 ret = net_setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &toggle, sizeof(toggle));
244 if (ret == -1)
245 {
246 net_error_out(fd, "net_set_keepalive");
247 }
248 return ret;
249 }
250
251
net_set_reuseaddress(int fd,int toggle)252 int net_set_reuseaddress(int fd, int toggle)
253 {
254 int ret;
255 ret = net_setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &toggle, sizeof(toggle));
256 if (ret == -1)
257 {
258 net_error_out(fd, "net_set_reuseaddress");
259 }
260 return ret;
261 }
262
net_set_sendbuf_size(int fd,size_t size)263 int net_set_sendbuf_size(int fd, size_t size)
264 {
265 return net_setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &size, sizeof(size));
266 }
267
net_get_sendbuf_size(int fd,size_t * size)268 int net_get_sendbuf_size(int fd, size_t* size)
269 {
270 socklen_t sz = sizeof(*size);
271 return net_getsockopt(fd, SOL_SOCKET, SO_SNDBUF, size, &sz);
272 }
273
net_set_recvbuf_size(int fd,size_t size)274 int net_set_recvbuf_size(int fd, size_t size)
275 {
276 return net_setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &size, sizeof(size));
277 }
278
net_get_recvbuf_size(int fd,size_t * size)279 int net_get_recvbuf_size(int fd, size_t* size)
280 {
281 socklen_t sz = sizeof(*size);
282 return net_getsockopt(fd, SOL_SOCKET, SO_RCVBUF, size, &sz);
283 }
284
285
286
net_close(int fd)287 int net_close(int fd)
288 {
289 #ifdef WINSOCK
290 int ret = closesocket(fd);
291 #else
292 int ret = close(fd);
293 #endif
294
295 if (ret == 0)
296 {
297 net_stats_add_close();
298 }
299 else
300 {
301 if (ret != -1)
302 {
303 net_stats_add_error();
304 }
305 }
306 return ret;
307 }
308
net_shutdown_r(int fd)309 int net_shutdown_r(int fd)
310 {
311 #ifdef WINSOCK
312 return shutdown(fd, SD_RECEIVE);
313 #else
314 return shutdown(fd, SHUT_RD);
315 #endif
316 }
317
net_shutdown_w(int fd)318 int net_shutdown_w(int fd)
319 {
320 #ifdef WINSOCK
321 return shutdown(fd, SD_SEND);
322 #else
323 return shutdown(fd, SHUT_WR);
324 #endif
325 }
326
net_shutdown_rw(int fd)327 int net_shutdown_rw(int fd)
328 {
329 #ifdef WINSOCK
330 return shutdown(fd, SD_BOTH);
331 #else
332 return shutdown(fd, SHUT_RDWR);
333 #endif
334 }
335
net_accept(int fd,struct ip_addr_encap * ipaddr)336 int net_accept(int fd, struct ip_addr_encap* ipaddr)
337 {
338 struct sockaddr_storage addr;
339 struct sockaddr_in* addr4;
340 struct sockaddr_in6* addr6;
341 socklen_t addr_size;
342 int ret = 0;
343 addr_size = sizeof(struct sockaddr_storage);
344
345 memset(&addr, 0, addr_size);
346 addr4 = (struct sockaddr_in*) &addr;
347 addr6 = (struct sockaddr_in6*) &addr;
348
349 ret = accept(fd, (struct sockaddr*) &addr, &addr_size);
350
351 if (ret == -1)
352 {
353 switch (net_error())
354 {
355 #if defined(__HAIKU__)
356 case ETIMEDOUT:
357 #endif
358 #if defined(__linux__)
359 case ENETDOWN:
360 case EPROTO:
361 case ENOPROTOOPT:
362 case EHOSTDOWN:
363 case ENONET:
364 case EHOSTUNREACH:
365 case EOPNOTSUPP:
366 errno = EWOULDBLOCK;
367 #endif
368 #ifdef WINSOCK
369 case WSAEWOULDBLOCK:
370 break;
371 #else
372 case EWOULDBLOCK:
373 break;
374 #endif
375 default:
376 net_error_out(fd, "net_accept");
377 net_stats_add_error();
378 return -1;
379 }
380 }
381 else
382 {
383 net_stats_add_accept();
384
385 if (ipaddr)
386 {
387 memset(ipaddr, 0, sizeof(struct ip_addr_encap));
388 ipaddr->af = addr.ss_family;;
389 if (ipaddr->af == AF_INET6)
390 {
391 char address[INET6_ADDRSTRLEN+1] = { 0, };
392 net_address_to_string(AF_INET6, (void*) &addr6->sin6_addr, address, INET6_ADDRSTRLEN+1);
393 if (strchr(address, '.'))
394 {
395 /* Hack to convert IPv6 mapped IPv4 addresses to true IPv4 addresses */
396 ipaddr->af = AF_INET;
397 net_string_to_address(AF_INET, address, (void*) &ipaddr->internal_ip_data.in);
398 }
399 else
400 {
401 memcpy(&ipaddr->internal_ip_data.in6, &addr6->sin6_addr, sizeof(struct in6_addr));
402 }
403 }
404 else
405 {
406 memcpy(&ipaddr->internal_ip_data.in, &addr4->sin_addr, sizeof(struct in_addr));
407 }
408 }
409 }
410
411 return ret;
412 }
413
414
net_connect(int fd,const struct sockaddr * serv_addr,socklen_t addrlen)415 int net_connect(int fd, const struct sockaddr *serv_addr, socklen_t addrlen)
416 {
417 int ret = connect(fd, serv_addr, addrlen);
418 if (ret == -1)
419 {
420 #ifdef WINSOCK
421 if (net_error() != WSAEINPROGRESS)
422 #else
423 if (net_error() != EINPROGRESS)
424 #endif
425 {
426 net_error_out(fd, "net_connect");
427 net_stats_add_error();
428 }
429 }
430 return ret;
431 }
432
433
434
net_is_ipv6_supported()435 int net_is_ipv6_supported()
436 {
437 if (is_ipv6_supported == -1)
438 {
439 int ret = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
440 if (ret == -1)
441 {
442 #ifdef WINSOCK
443 if (net_error() == WSAEAFNOSUPPORT)
444 #else
445 if (net_error() == EAFNOSUPPORT)
446 #endif
447 {
448 LOG_TRACE("net_is_ipv6_supported(): IPv6 is not supported on this system.");
449 is_ipv6_supported = 0;
450 return 0;
451 }
452
453 net_error_out(ret, "net_is_ipv6_supported");
454 }
455 else
456 {
457 #ifdef SOCK_DUAL_STACK_OPT
458 int off = 0;
459 if (net_setsockopt(ret, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
460 {
461 LOG_ERROR("net_socket_create(): Dual stack IPv6/IPv4 is not supported.");
462 is_ipv6_supported = 0;
463 }
464 else
465 {
466 is_ipv6_supported = 1;
467 }
468 #else
469 is_ipv6_supported = 0;
470 #endif
471 net_close(ret);
472 }
473 }
474 return is_ipv6_supported;
475 }
476
477
net_socket_create(int af,int type,int protocol)478 int net_socket_create(int af, int type, int protocol)
479 {
480 int sd = socket(af, type, protocol);
481 if (sd == -1)
482 {
483 net_error_out(sd, "net_socket_create");
484 return -1;
485 }
486
487 #ifdef SOCK_DUAL_STACK_OPT
488 /* BSD style */
489 if (af == AF_INET6)
490 {
491 int off = 0;
492 if (net_setsockopt(sd, IPPROTO_IPV6, SOCK_DUAL_STACK_OPT, (char*) &off, sizeof(off)) < 0)
493 {
494 LOG_ERROR("net_socket_create(): Cannot set socket to dual stack mode IPv6/IPv4 (%d - %s).", net_error(), net_error_string(net_error()));
495 }
496 }
497 #endif
498 return sd;
499 }
500
net_address_to_string(int af,const void * src,char * dst,socklen_t cnt)501 const char* net_address_to_string(int af, const void* src, char* dst, socklen_t cnt)
502 {
503 #ifdef WINSOCK
504 struct sockaddr_in sin4;
505 struct sockaddr_in6 sin6;
506 struct in_addr* addr4 = (struct in_addr*) src;
507 struct in6_addr* addr6 = (struct in6_addr*) src;
508 size_t size;
509 LPSOCKADDR addr;
510 DWORD len = cnt;
511
512 switch (af)
513 {
514 case AF_INET:
515 sin4.sin_family = AF_INET;
516 sin4.sin_port = 0;
517 sin4.sin_addr = *addr4;
518 size = sizeof(sin4);
519 addr = (LPSOCKADDR) &sin4;
520 break;
521
522 case AF_INET6:
523 sin6.sin6_family = AF_INET6;
524 sin6.sin6_port = 0;
525 sin6.sin6_addr = *addr6;
526 sin6.sin6_scope_id = 0;
527 size = sizeof(sin6);
528 addr = (LPSOCKADDR) &sin6;
529 break;
530
531 default:
532 return NULL;
533 }
534
535 if (WSAAddressToStringA(addr, size, NULL, dst, &len) == 0)
536 {
537 return dst;
538 }
539
540 return NULL;
541 #else
542 if (inet_ntop(af, src, dst, cnt))
543 {
544 if (af == AF_INET6 && strncmp(dst, "::ffff:", 7) == 0) /* IPv6 mapped IPv4 address. */
545 {
546 memmove(dst, dst + 7, cnt - 7);
547 }
548 return dst;
549 }
550 return NULL;
551 #endif
552 }
553
net_string_to_address(int af,const char * src,void * dst)554 int net_string_to_address(int af, const char* src, void* dst)
555 {
556 #ifdef WINSOCK
557 int ret, size;
558 struct sockaddr_in addr4;
559 struct sockaddr_in6 addr6;
560 struct sockaddr* addr = 0;
561 if (af == AF_INET6)
562 {
563 if (net_is_ipv6_supported() != 1) return -1;
564 size = sizeof(struct sockaddr_in6);
565 addr = (struct sockaddr*) &addr6;
566 }
567 else
568 {
569 size = sizeof(struct sockaddr_in);
570 addr = (struct sockaddr*) &addr4;
571 }
572
573 if (!net_initialized)
574 net_initialize();
575
576 ret = WSAStringToAddressA((char*) src, af, NULL, addr, &size);
577 if (ret == -1)
578 {
579 return -1;
580 }
581
582 if (af == AF_INET6)
583 {
584 memcpy(dst, &addr6.sin6_addr, sizeof(addr6.sin6_addr));
585 }
586 else
587 {
588 memcpy(dst, &addr4.sin_addr, sizeof(addr4.sin_addr));
589 }
590
591 return 1;
592 #else
593 return inet_pton(af, src, dst);
594 #endif
595 }
596
net_get_peer_address(int fd)597 const char* net_get_peer_address(int fd)
598 {
599 static char address[INET6_ADDRSTRLEN+1];
600 struct sockaddr_storage storage;
601 struct sockaddr_in6* name6;
602 struct sockaddr_in* name4;
603 struct sockaddr* name;
604 socklen_t namelen;
605
606 memset(address, 0, INET6_ADDRSTRLEN);
607 namelen = sizeof(struct sockaddr_storage);
608 memset(&storage, 0, namelen);
609
610 name6 = (struct sockaddr_in6*) &storage;
611 name4 = (struct sockaddr_in*) &storage;
612 name = (struct sockaddr*) &storage;
613
614 if (getpeername(fd, (struct sockaddr*) name, &namelen) != -1)
615 {
616 int af = storage.ss_family;
617 if (af == AF_INET6)
618 {
619 net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
620 }
621 else
622 {
623 net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
624 }
625 return address;
626 }
627 else
628 {
629 net_error_out(fd, "net_get_peer_address");
630 net_stats_add_error();
631 }
632
633 return "0.0.0.0";
634 }
635
net_get_local_address(int fd)636 const char* net_get_local_address(int fd)
637 {
638 static char address[INET6_ADDRSTRLEN+1];
639 struct sockaddr_storage storage;
640 struct sockaddr_in6* name6;
641 struct sockaddr_in* name4;
642 struct sockaddr* name;
643 socklen_t namelen;
644
645 memset(address, 0, INET6_ADDRSTRLEN);
646 namelen = sizeof(struct sockaddr_storage);
647 memset(&storage, 0, namelen);
648
649 name6 = (struct sockaddr_in6*) &storage;
650 name4 = (struct sockaddr_in*) &storage;
651 name = (struct sockaddr*) &storage;
652
653 if (getsockname(fd, (struct sockaddr*) name, &namelen) != -1)
654 {
655 #ifndef WINSOCK
656 int af = storage.ss_family;
657 if (af == AF_INET6)
658 {
659 net_address_to_string(af, (void*) &name6->sin6_addr, address, INET6_ADDRSTRLEN);
660 }
661 else
662 #else
663 int af = AF_INET;
664 #endif
665 {
666 net_address_to_string(af, (void*) &name4->sin_addr, address, INET6_ADDRSTRLEN);
667 }
668 return address;
669 }
670 else
671 {
672 net_error_out(fd, "net_get_local_address");
673 net_stats_add_error();
674 }
675
676 return "0.0.0.0";
677 }
678
679
680
net_recv(int fd,void * buf,size_t len,int flags)681 ssize_t net_recv(int fd, void* buf, size_t len, int flags)
682 {
683 ssize_t ret = recv(fd, buf, len, flags);
684 if (ret >= 0)
685 {
686 net_stats_add_rx(ret);
687 }
688 else
689 {
690 #ifdef WINSOCK
691 if (net_error() != WSAEWOULDBLOCK)
692 #else
693 if (net_error() != EWOULDBLOCK)
694 #endif
695 {
696 /* net_error_out(fd, "net_recv"); */
697 net_stats_add_error();
698 }
699 }
700 return ret;
701 }
702
703
net_send(int fd,const void * buf,size_t len,int flags)704 ssize_t net_send(int fd, const void* buf, size_t len, int flags)
705 {
706 ssize_t ret = send(fd, buf, len, flags);
707 if (ret >= 0)
708 {
709 net_stats_add_tx(ret);
710 }
711 else
712 {
713 #ifdef WINSOCK
714 if (net_error() != WSAEWOULDBLOCK)
715 #else
716 if (net_error() != EWOULDBLOCK)
717 #endif
718 {
719 /* net_error_out(fd, "net_send"); */
720 net_stats_add_error();
721 }
722 }
723 return ret;
724 }
725
726
net_bind(int fd,const struct sockaddr * my_addr,socklen_t addrlen)727 int net_bind(int fd, const struct sockaddr *my_addr, socklen_t addrlen)
728 {
729 int ret = bind(fd, my_addr, addrlen);
730 if (ret == -1)
731 {
732 net_error_out(fd, "net_bind");
733 net_stats_add_error();
734 }
735 return ret;
736 }
737
738
net_listen(int fd,int backlog)739 int net_listen(int fd, int backlog)
740 {
741 int ret = listen(fd, backlog);
742 if (ret == -1)
743 {
744 net_error_out(fd, "net_listen");
745 net_stats_add_error();
746 }
747 return ret;
748 }
749
750
net_stats_initialize()751 void net_stats_initialize()
752 {
753 memset(&stats_total, 0, sizeof(struct net_statistics));
754 stats_total.timestamp = time(NULL);
755
756 memset(&stats, 0, sizeof(struct net_statistics));
757 stats.timestamp = time(NULL);
758 }
759
net_stats_get(struct net_statistics ** intermediate,struct net_statistics ** total)760 void net_stats_get(struct net_statistics** intermediate, struct net_statistics** total)
761 {
762 *intermediate = &stats;
763 *total = &stats_total;
764 }
765
net_stats_reset()766 void net_stats_reset()
767 {
768 stats_total.tx += stats.tx;
769 stats_total.rx += stats.rx;
770 stats_total.accept += stats.accept;
771 stats_total.errors += stats.errors;
772 stats_total.closed += stats.closed;
773
774 memset(&stats, 0, sizeof(struct net_statistics));
775 stats.timestamp = time(NULL);
776 }
777
net_stats_timeout()778 int net_stats_timeout()
779 {
780 return (difftime(time(NULL), stats.timestamp) > TIMEOUT_STATS) ? 1 : 0;
781 }
782
net_stats_add_tx(size_t bytes)783 void net_stats_add_tx(size_t bytes)
784 {
785 stats.tx += bytes;
786 }
787
net_stats_add_rx(size_t bytes)788 void net_stats_add_rx(size_t bytes)
789 {
790 stats.rx += bytes;
791 }
792
net_stats_add_accept()793 void net_stats_add_accept()
794 {
795 stats.accept++;
796 }
797
net_stats_add_error()798 void net_stats_add_error()
799 {
800 stats.errors++;
801 }
802
net_stats_add_close()803 void net_stats_add_close()
804 {
805 stats.closed++;
806 }
807
808
809