2 mtr -- a network diagnostic tool
3 Copyright (C) 2016 Matt Kimball
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.
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.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include <netinet/in.h>
23 #include <sys/socket.h>
26 #include "packet/protocols.h"
28 #define MAX_PACKET_SIZE 9000
31 The first probe sent by mtr-packet will have this sequence number,
32 so wait for an ICMP packet with this sequence ID.
34 #define SEQUENCE_NUM 33000
37 Check to see if the packet we've received is intended for this test
38 process. We expected the ICMP sequence number to be equal to our
41 bool is_packet_for_us4(
45 int ip_icmp_size
= sizeof(struct IPHeader
) + sizeof(struct ICMPHeader
);
46 int expected_sequence
;
48 struct ICMPHeader
*icmp
;
50 if (packet_size
< ip_icmp_size
) {
54 ip
= (struct IPHeader
*)packet
;
55 icmp
= (struct ICMPHeader
*)(ip
+ 1);
57 expected_sequence
= htons(SEQUENCE_NUM
);
58 if (icmp
->sequence
== expected_sequence
) {
66 Check to see if the ICMPv6 packet is for us.
67 Unlike ICMPv4 packets, ICMPv6 packets don't include the IP header.
69 bool is_packet_for_us6(
73 int expected_sequence
;
74 struct ICMPHeader
*icmp
;
76 if (packet_size
< sizeof(struct ICMPHeader
)) {
80 icmp
= (struct ICMPHeader
*)packet
;
82 expected_sequence
= htons(SEQUENCE_NUM
);
83 if (icmp
->sequence
== expected_sequence
) {
91 Check that all the bytes in the body of the packet have the same value.
92 If so, return that value. If not, return -1.
94 int get_packet_pattern(
95 unsigned char *packet
,
101 if (packet_size
<= 0) {
105 fill_value
= packet
[0];
106 for (i
= 1; i
< packet_size
; i
++) {
107 if (packet
[i
] != fill_value
) {
115 /* Print information about the ICMPv4 packet we received */
116 void dump_packet_info4(
120 int ip_icmp_size
= sizeof(struct IPHeader
) + sizeof(struct ICMPHeader
);
123 struct ICMPHeader
*icmp
;
127 ip
= (struct IPHeader
*)packet
;
128 icmp
= (struct ICMPHeader
*)(ip
+ 1);
129 body
= (unsigned char *)(icmp
+ 1);
130 body_size
= packet_size
- ip_icmp_size
;
132 printf("size %d\n", packet_size
);
133 printf("tos %d\n", ip
->tos
);
135 pattern
= get_packet_pattern(body
, body_size
);
137 printf("bitpattern none\n");
139 printf("bitpattern %d\n", pattern
);
143 /* Print information about an ICMPv6 packet */
144 void dump_packet_info6(
149 struct ICMPHeader
*icmp
;
154 icmp
= (struct ICMPHeader
*)packet
;
155 body
= (unsigned char *)(icmp
+ 1);
156 body_size
= packet_size
- sizeof(struct ICMPHeader
);
158 total_size
= packet_size
+ sizeof(struct IP6Header
);
159 printf("size %d\n", total_size
);
161 pattern
= get_packet_pattern(body
, body_size
);
163 printf("bitpattern none\n");
165 printf("bitpattern %d\n", pattern
);
169 /* Receive ICMP packets until we get one intended for this test process */
170 void loop_on_receive(
175 char packet
[MAX_PACKET_SIZE
];
178 packet_size
= recv(icmp_socket
, packet
, MAX_PACKET_SIZE
, 0);
179 if (packet_size
< -1) {
180 perror("Failure during receive");
184 if (ip_version
== 6) {
185 if (is_packet_for_us6(packet
, packet_size
)) {
186 dump_packet_info6(packet
, packet_size
);
190 if (is_packet_for_us4(packet
, packet_size
)) {
191 dump_packet_info4(packet
, packet_size
);
198 /* Parse the commandline arguments */
208 while ((opt
= getopt(argc
, argv
, "46")) != -1) {
220 A helper for mtr-packet testing which waits for an ICMP packet
221 intended for this test process, and then prints information about
231 parse_cmdline(argc
, argv
, &ip_version
);
233 if (ip_version
== 6) {
234 icmp_socket
= socket(AF_INET6
, SOCK_RAW
, IPPROTO_ICMPV6
);
236 icmp_socket
= socket(AF_INET
, SOCK_RAW
, IPPROTO_ICMP
);
238 if (icmp_socket
< 0) {
239 perror("Failure opening listening socket");
243 printf("status listening\n");
246 loop_on_receive(icmp_socket
, ip_version
);