Annotation of embedaddon/mtr/packet/probe_unix.c, revision 1.1.1.1
1.1 misho 1: /*
2: mtr -- a network diagnostic tool
3: Copyright (C) 2016 Matt Kimball
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 version 2 as
7: published by the Free Software Foundation.
8:
9: This program is distributed in the hope that it will be useful,
10: but WITHOUT ANY WARRANTY; without even the implied warranty of
11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12: GNU General Public License for more details.
13:
14: You should have received a copy of the GNU General Public License
15: along with this program; if not, write to the Free Software
16: Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17: */
18:
19: #include "probe.h"
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <stdio.h>
25: #include <stdlib.h>
26: #include <string.h>
27: #include <sys/socket.h>
28: #include <unistd.h>
29:
30: #include "platform.h"
31: #include "protocols.h"
32: #include "construct_unix.h"
33: #include "deconstruct_unix.h"
34: #include "timeval.h"
35:
36: /* A wrapper around sendto for mixed IPv4 and IPv6 sending */
37: static
38: int send_packet(
39: const struct net_state_t *net_state,
40: const struct probe_param_t *param,
41: const char *packet,
42: int packet_size,
43: const struct sockaddr_storage *sockaddr)
44: {
45: int send_socket = 0;
46: int sockaddr_length;
47:
48: if (sockaddr->ss_family == AF_INET6) {
49: sockaddr_length = sizeof(struct sockaddr_in6);
50:
51: if (param->protocol == IPPROTO_ICMP) {
52: send_socket = net_state->platform.icmp6_send_socket;
53: } else if (param->protocol == IPPROTO_UDP) {
54: send_socket = net_state->platform.udp6_send_socket;
55: }
56: } else if (sockaddr->ss_family == AF_INET) {
57: sockaddr_length = sizeof(struct sockaddr_in);
58:
59: send_socket = net_state->platform.ip4_send_socket;
60: }
61:
62: if (send_socket == 0) {
63: errno = EINVAL;
64: return -1;
65: }
66:
67: return sendto(send_socket, packet, packet_size, 0,
68: (struct sockaddr *) sockaddr, sockaddr_length);
69: }
70:
71: /*
72: Nearly all fields in the IP header should be encoded in network byte
73: order prior to passing to send(). However, the required byte order of
74: the length field of the IP header is inconsistent between operating
75: systems and operating system versions. FreeBSD 11 requires the length
76: field in network byte order, but some older versions of FreeBSD
77: require host byte order. OS X requires the length field in host
78: byte order. Linux will accept either byte order.
79:
80: Test for a byte order which works by sending a ping to localhost.
81: */
82: static
83: void check_length_order(
84: struct net_state_t *net_state)
85: {
86: char packet[PACKET_BUFFER_SIZE];
87: struct probe_param_t param;
88: struct sockaddr_storage dest_sockaddr;
89: struct sockaddr_storage src_sockaddr;
90: ssize_t bytes_sent;
91: int packet_size;
92:
93: memset(¶m, 0, sizeof(struct probe_param_t));
94: param.ip_version = 4;
95: param.protocol = IPPROTO_ICMP;
96: param.ttl = 255;
97: param.remote_address = "127.0.0.1";
98:
99: if (resolve_probe_addresses(¶m, &dest_sockaddr, &src_sockaddr)) {
100: fprintf(stderr, "Error decoding localhost address\n");
101: exit(EXIT_FAILURE);
102: }
103:
104: /* First attempt to ping the localhost with network byte order */
105: net_state->platform.ip_length_host_order = false;
106:
107: packet_size = construct_packet(net_state, NULL, MIN_PORT,
108: packet, PACKET_BUFFER_SIZE,
109: &dest_sockaddr, &src_sockaddr, ¶m);
110: if (packet_size < 0) {
111: perror("Unable to send to localhost");
112: exit(EXIT_FAILURE);
113: }
114:
115: bytes_sent =
116: send_packet(net_state, ¶m, packet, packet_size,
117: &dest_sockaddr);
118: if (bytes_sent > 0) {
119: return;
120: }
121:
122: /* Since network byte order failed, try host byte order */
123: net_state->platform.ip_length_host_order = true;
124:
125: packet_size = construct_packet(net_state, NULL, MIN_PORT,
126: packet, PACKET_BUFFER_SIZE,
127: &dest_sockaddr, &src_sockaddr, ¶m);
128: if (packet_size < 0) {
129: perror("Unable to send to localhost");
130: exit(EXIT_FAILURE);
131: }
132:
133: bytes_sent =
134: send_packet(net_state, ¶m, packet, packet_size,
135: &dest_sockaddr);
136: if (bytes_sent < 0) {
137: perror("Unable to send with swapped length");
138: exit(EXIT_FAILURE);
139: }
140: }
141:
142: /*
143: Check to see if SCTP is support. We can't just rely on checking
144: if IPPROTO_SCTP is defined, because while that is necessary,
145: MacOS as of "Sierra" defines IPPROTO_SCTP, but creating an SCTP
146: socket results in an error.
147: */
148: static
149: void check_sctp_support(
150: struct net_state_t *net_state)
151: {
152: #ifdef IPPROTO_SCTP
153: int sctp_socket;
154:
155: sctp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP);
156: if (sctp_socket != -1) {
157: close(sctp_socket);
158:
159: net_state->platform.sctp_support = true;
160: }
161: #endif
162: }
163:
164: /* Set a socket to non-blocking mode */
165: void set_socket_nonblocking(
166: int socket)
167: {
168: int flags;
169:
170: flags = fcntl(socket, F_GETFL, 0);
171: if (flags == -1) {
172: perror("Unexpected socket F_GETFL error");
173: exit(EXIT_FAILURE);
174: }
175:
176: if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {
177: perror("Unexpected socket F_SETFL O_NONBLOCK error");
178: exit(EXIT_FAILURE);
179: }
180: }
181:
182: /* Open the raw sockets for sending/receiving IPv4 packets */
183: static
184: int open_ip4_sockets(
185: struct net_state_t *net_state)
186: {
187: int send_socket;
188: int recv_socket;
189: int trueopt = 1;
190:
191: send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
192: if (send_socket == -1) {
193: return -1;
194: }
195:
196: /*
197: We will be including the IP header in transmitted packets.
198: Linux doesn't require this, but BSD derived network stacks do.
199: */
200: if (setsockopt
201: (send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) {
202:
203: close(send_socket);
204: return -1;
205: }
206:
207: /*
208: Open a second socket with IPPROTO_ICMP because we are only
209: interested in receiving ICMP packets, not all packets.
210: */
211: recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
212: if (recv_socket == -1) {
213: close(send_socket);
214: return -1;
215: }
216:
217: net_state->platform.ip4_present = true;
218: net_state->platform.ip4_send_socket = send_socket;
219: net_state->platform.ip4_recv_socket = recv_socket;
220:
221: return 0;
222: }
223:
224: /* Open the raw sockets for sending/receiving IPv6 packets */
225: static
226: int open_ip6_sockets(
227: struct net_state_t *net_state)
228: {
229: int send_socket_icmp;
230: int send_socket_udp;
231: int recv_socket;
232:
233: send_socket_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
234: if (send_socket_icmp == -1) {
235: return -1;
236: }
237:
238: send_socket_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
239: if (send_socket_udp == -1) {
240: close(send_socket_icmp);
241:
242: return -1;
243: }
244:
245: recv_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
246: if (recv_socket == -1) {
247: close(send_socket_icmp);
248: close(send_socket_udp);
249:
250: return -1;
251: }
252:
253: net_state->platform.ip6_present = true;
254: net_state->platform.icmp6_send_socket = send_socket_icmp;
255: net_state->platform.udp6_send_socket = send_socket_udp;
256: net_state->platform.ip6_recv_socket = recv_socket;
257:
258: return 0;
259: }
260:
261: /*
262: The first half of the net state initialization. Since this
263: happens with elevated privileges, this is kept as minimal
264: as possible to minimize security risk.
265: */
266: void init_net_state_privileged(
267: struct net_state_t *net_state)
268: {
269: int ip4_err = 0;
270: int ip6_err = 0;
271:
272: memset(net_state, 0, sizeof(struct net_state_t));
273:
274: net_state->platform.next_sequence = MIN_PORT;
275:
276: if (open_ip4_sockets(net_state)) {
277: ip4_err = errno;
278: }
279: if (open_ip6_sockets(net_state)) {
280: ip6_err = errno;
281: }
282:
283: /*
284: If we couldn't open either IPv4 or IPv6 sockets, we can't do
285: much, so print errors and exit.
286: */
287: if (!net_state->platform.ip4_present
288: && !net_state->platform.ip6_present) {
289:
290: errno = ip4_err;
291: perror("Failure to open IPv4 sockets");
292:
293: errno = ip6_err;
294: perror("Failure to open IPv6 sockets");
295:
296: exit(EXIT_FAILURE);
297: }
298: }
299:
300: /*
301: The second half of net state initialization, which is run
302: at normal privilege levels.
303: */
304: void init_net_state(
305: struct net_state_t *net_state)
306: {
307: set_socket_nonblocking(net_state->platform.ip4_recv_socket);
308: set_socket_nonblocking(net_state->platform.ip6_recv_socket);
309:
310: if (net_state->platform.ip4_present) {
311: check_length_order(net_state);
312: }
313:
314: check_sctp_support(net_state);
315: }
316:
317: /*
318: Returns true if we were able to open sockets for a particular
319: IP protocol version.
320: */
321: bool is_ip_version_supported(
322: struct net_state_t *net_state,
323: int ip_version)
324: {
325: if (ip_version == 4) {
326: return net_state->platform.ip4_present;
327: } else if (ip_version == 6) {
328: return net_state->platform.ip6_present;
329: } else {
330: return false;
331: }
332: }
333:
334: /* Returns true if we can transmit probes using the specified protocol */
335: bool is_protocol_supported(
336: struct net_state_t * net_state,
337: int protocol)
338: {
339: if (protocol == IPPROTO_ICMP) {
340: return true;
341: }
342:
343: if (protocol == IPPROTO_UDP) {
344: return true;
345: }
346:
347: if (protocol == IPPROTO_TCP) {
348: return true;
349: }
350: #ifdef IPPROTO_SCTP
351: if (protocol == IPPROTO_SCTP) {
352: return net_state->platform.sctp_support;
353: }
354: #endif
355:
356: return false;
357: }
358:
359: /* Report an error during send_probe based on the errno value */
360: static
361: void report_packet_error(
362: int command_token)
363: {
364: if (errno == EINVAL) {
365: printf("%d invalid-argument\n", command_token);
366: } else if (errno == ENETDOWN) {
367: printf("%d network-down\n", command_token);
368: } else if (errno == ENETUNREACH) {
369: printf("%d no-route\n", command_token);
370: } else if (errno == EHOSTUNREACH) {
371: printf("%d no-route\n", command_token);
372: } else if (errno == EPERM) {
373: printf("%d permission-denied\n", command_token);
374: } else if (errno == EADDRINUSE) {
375: printf("%d address-in-use\n", command_token);
376: } else if (errno == EADDRNOTAVAIL) {
377: printf("%d address-not-available\n", command_token);
378: } else {
379: printf("%d unexpected-error errno %d\n", command_token, errno);
380: }
381: }
382:
383: /* Craft a custom ICMP packet for a network probe. */
384: void send_probe(
385: struct net_state_t *net_state,
386: const struct probe_param_t *param)
387: {
388: char packet[PACKET_BUFFER_SIZE];
389: struct probe_t *probe;
390: int packet_size;
391: struct sockaddr_storage src_sockaddr;
392:
393: probe = alloc_probe(net_state, param->command_token);
394: if (probe == NULL) {
395: printf("%d probes-exhausted\n", param->command_token);
396: return;
397: }
398:
399: if (resolve_probe_addresses(param, &probe->remote_addr, &src_sockaddr)) {
400: printf("%d invalid-argument\n", param->command_token);
401: free_probe(net_state, probe);
402: return;
403: }
404:
405: if (gettimeofday(&probe->platform.departure_time, NULL)) {
406: perror("gettimeofday failure");
407: exit(EXIT_FAILURE);
408: }
409:
410: packet_size =
411: construct_packet(net_state, &probe->platform.socket,
412: probe->sequence, packet, PACKET_BUFFER_SIZE,
413: &probe->remote_addr, &src_sockaddr, param);
414:
415: if (packet_size < 0) {
416: /*
417: When using a stream protocol, FreeBSD will return ECONNREFUSED
418: when connecting to localhost if the port doesn't exist,
419: even if the socket is non-blocking, so we should be
420: prepared for that.
421: */
422: if (errno == ECONNREFUSED) {
423: receive_probe(net_state, probe, ICMP_ECHOREPLY,
424: &probe->remote_addr, NULL, 0, NULL);
425: } else {
426: report_packet_error(param->command_token);
427: free_probe(net_state, probe);
428: }
429:
430: return;
431: }
432:
433: if (packet_size > 0) {
434: if (send_packet(net_state, param,
435: packet, packet_size, &probe->remote_addr) == -1) {
436:
437: report_packet_error(param->command_token);
438: free_probe(net_state, probe);
439: return;
440: }
441: }
442:
443: probe->platform.timeout_time = probe->platform.departure_time;
444: probe->platform.timeout_time.tv_sec += param->timeout;
445: }
446:
447: /* When allocating a probe, assign it a unique port number */
448: void platform_alloc_probe(
449: struct net_state_t *net_state,
450: struct probe_t *probe)
451: {
452: probe->sequence = net_state->platform.next_sequence++;
453:
454: if (net_state->platform.next_sequence > MAX_PORT) {
455: net_state->platform.next_sequence = MIN_PORT;
456: }
457: }
458:
459: /*
460: When freeing the probe, close the socket for the probe,
461: if one has been opened
462: */
463: void platform_free_probe(
464: struct probe_t *probe)
465: {
466: if (probe->platform.socket) {
467: close(probe->platform.socket);
468: probe->platform.socket = 0;
469: }
470: }
471:
472: /*
473: Compute the round trip time of a just-received probe and pass it
474: to the platform agnostic response handling.
475: */
476: void receive_probe(
477: struct net_state_t *net_state,
478: struct probe_t *probe,
479: int icmp_type,
480: const struct sockaddr_storage *remote_addr,
481: struct timeval *timestamp,
482: int mpls_count,
483: struct mpls_label_t *mpls)
484: {
485: unsigned int round_trip_us;
486: struct timeval *departure_time = &probe->platform.departure_time;
487: struct timeval now;
488:
489: if (timestamp == NULL) {
490: if (gettimeofday(&now, NULL)) {
491: perror("gettimeofday failure");
492: exit(EXIT_FAILURE);
493: }
494:
495: timestamp = &now;
496: }
497:
498: round_trip_us =
499: (timestamp->tv_sec - departure_time->tv_sec) * 1000000 +
500: timestamp->tv_usec - departure_time->tv_usec;
501:
502: respond_to_probe(net_state, probe, icmp_type,
503: remote_addr, round_trip_us, mpls_count, mpls);
504: }
505:
506: /*
507: Read all available packets through our receiving raw socket, and
508: handle any responses to probes we have preivously sent.
509: */
510: static
511: void receive_replies_from_icmp_socket(
512: struct net_state_t *net_state,
513: int socket,
514: received_packet_func_t handle_received_packet)
515: {
516: char packet[PACKET_BUFFER_SIZE];
517: int packet_length;
518: struct sockaddr_storage remote_addr;
519: socklen_t sockaddr_length;
520: struct timeval timestamp;
521:
522: /* Read until no more packets are available */
523: while (true) {
524: sockaddr_length = sizeof(struct sockaddr_storage);
525: packet_length = recvfrom(socket, packet, PACKET_BUFFER_SIZE, 0,
526: (struct sockaddr *) &remote_addr,
527: &sockaddr_length);
528:
529: /*
530: Get the time immediately after reading the packet to
531: keep the timing as precise as we can.
532: */
533: if (gettimeofday(×tamp, NULL)) {
534: perror("gettimeofday failure");
535: exit(EXIT_FAILURE);
536: }
537:
538: if (packet_length == -1) {
539: /*
540: EAGAIN will be returned if there is no current packet
541: available.
542: */
543: if (errno == EAGAIN) {
544: return;
545: }
546:
547: /*
548: EINTER will be returned if we received a signal during
549: receive.
550: */
551: if (errno == EINTR) {
552: continue;
553: }
554:
555: perror("Failure receiving replies");
556: exit(EXIT_FAILURE);
557: }
558:
559: handle_received_packet(net_state, &remote_addr, packet,
560: packet_length, ×tamp);
561: }
562: }
563:
564: /*
565: Attempt to send using the probe's socket, in order to check whether
566: the connection has completed, for stream oriented protocols such as
567: TCP.
568: */
569: static
570: void receive_replies_from_probe_socket(
571: struct net_state_t *net_state,
572: struct probe_t *probe)
573: {
574: int probe_socket;
575: struct timeval zero_time;
576: int err;
577: int err_length = sizeof(int);
578: fd_set write_set;
579:
580: probe_socket = probe->platform.socket;
581: if (!probe_socket) {
582: return;
583: }
584:
585: FD_ZERO(&write_set);
586: FD_SET(probe_socket, &write_set);
587:
588: zero_time.tv_sec = 0;
589: zero_time.tv_usec = 0;
590:
591: if (select(probe_socket + 1, NULL, &write_set, NULL, &zero_time) == -1) {
592: if (errno == EAGAIN) {
593: return;
594: } else {
595: perror("probe socket select error");
596: exit(EXIT_FAILURE);
597: }
598: }
599:
600: /*
601: If the socket is writable, the connection attempt has completed.
602: */
603: if (!FD_ISSET(probe_socket, &write_set)) {
604: return;
605: }
606:
607: if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {
608: perror("probe socket SO_ERROR");
609: exit(EXIT_FAILURE);
610: }
611:
612: /*
613: If the connection complete successfully, or was refused, we can
614: assume our probe arrived at the destination.
615: */
616: if (!err || err == ECONNREFUSED) {
617: receive_probe(net_state, probe, ICMP_ECHOREPLY,
618: &probe->remote_addr, NULL, 0, NULL);
619: } else {
620: errno = err;
621: report_packet_error(probe->token);
622: free_probe(net_state, probe);
623: }
624: }
625:
626: /* Check both the IPv4 and IPv6 sockets for incoming packets */
627: void receive_replies(
628: struct net_state_t *net_state)
629: {
630: struct probe_t *probe;
631: struct probe_t *probe_safe_iter;
632:
633: if (net_state->platform.ip4_present) {
634: receive_replies_from_icmp_socket(net_state,
635: net_state->platform.
636: ip4_recv_socket,
637: handle_received_ip4_packet);
638: }
639:
640: if (net_state->platform.ip6_present) {
641: receive_replies_from_icmp_socket(net_state,
642: net_state->platform.
643: ip6_recv_socket,
644: handle_received_ip6_packet);
645: }
646:
647: LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
648: probe_list_entry, probe_safe_iter) {
649:
650: receive_replies_from_probe_socket(net_state, probe);
651: }
652: }
653:
654: /*
655: Put all of our probe sockets in the read set used for an upcoming
656: select so we can wake when any of them become readable.
657: */
658: int gather_probe_sockets(
659: const struct net_state_t *net_state,
660: fd_set * write_set)
661: {
662: int probe_socket;
663: int nfds;
664: const struct probe_t *probe;
665:
666: nfds = 0;
667:
668: LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
669: probe_socket = probe->platform.socket;
670:
671: if (probe_socket) {
672: FD_SET(probe_socket, write_set);
673: if (probe_socket >= nfds) {
674: nfds = probe_socket + 1;
675: }
676: }
677: }
678:
679: return nfds;
680: }
681:
682: /*
683: Check for any probes for which we have not received a response
684: for some time, and report a time-out, assuming that we won't
685: receive a future reply.
686: */
687: void check_probe_timeouts(
688: struct net_state_t *net_state)
689: {
690: struct timeval now;
691: struct probe_t *probe;
692: struct probe_t *probe_safe_iter;
693:
694: if (gettimeofday(&now, NULL)) {
695: perror("gettimeofday failure");
696: exit(EXIT_FAILURE);
697: }
698:
699: LIST_FOREACH_SAFE(probe, &net_state->outstanding_probes,
700: probe_list_entry, probe_safe_iter) {
701:
702: if (compare_timeval(probe->platform.timeout_time, now) < 0) {
703: /* Report timeout to the command stream */
704: printf("%d no-reply\n", probe->token);
705:
706: free_probe(net_state, probe);
707: }
708: }
709: }
710:
711: /*
712: Find the remaining time until the next probe times out.
713: This may be a negative value if the next probe timeout has
714: already elapsed.
715:
716: Returns false if no probes are currently outstanding, and true
717: if a timeout value for the next probe exists.
718: */
719: bool get_next_probe_timeout(
720: const struct net_state_t *net_state,
721: struct timeval *timeout)
722: {
723: bool have_timeout;
724: const struct probe_t *probe;
725: struct timeval now;
726: struct timeval probe_timeout;
727:
728: if (gettimeofday(&now, NULL)) {
729: perror("gettimeofday failure");
730: exit(EXIT_FAILURE);
731: }
732:
733: have_timeout = false;
734: LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
735: probe_timeout.tv_sec =
736: probe->platform.timeout_time.tv_sec - now.tv_sec;
737: probe_timeout.tv_usec =
738: probe->platform.timeout_time.tv_usec - now.tv_usec;
739:
740: normalize_timeval(&probe_timeout);
741: if (have_timeout) {
742: if (compare_timeval(probe_timeout, *timeout) < 0) {
743: /* If this probe has a sooner timeout, store it instead */
744: *timeout = probe_timeout;
745: }
746: } else {
747: *timeout = probe_timeout;
748: have_timeout = true;
749: }
750: }
751:
752: return have_timeout;
753: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>