Changed how conflicitng first/max TTL works.
[mtr.git] / test / packet_listen.c
blob9a1d931c5310ca306807d8bcec6d3c596487b9c6
1 /*
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>
20 #include <stdbool.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <sys/socket.h>
24 #include <unistd.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
39 process ID.
41 bool is_packet_for_us4(
42 char *packet,
43 int packet_size)
45 int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
46 int expected_sequence;
47 struct IPHeader *ip;
48 struct ICMPHeader *icmp;
50 if (packet_size < ip_icmp_size) {
51 return false;
54 ip = (struct IPHeader *)packet;
55 icmp = (struct ICMPHeader *)(ip + 1);
57 expected_sequence = htons(SEQUENCE_NUM);
58 if (icmp->sequence == expected_sequence) {
59 return true;
62 return false;
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(
70 char *packet,
71 int packet_size)
73 int expected_sequence;
74 struct ICMPHeader *icmp;
76 if (packet_size < sizeof(struct ICMPHeader)) {
77 return false;
80 icmp = (struct ICMPHeader *)packet;
82 expected_sequence = htons(SEQUENCE_NUM);
83 if (icmp->sequence == expected_sequence) {
84 return true;
87 return false;
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,
96 int packet_size)
98 int fill_value;
99 int i;
101 if (packet_size <= 0) {
102 return -1;
105 fill_value = packet[0];
106 for (i = 1; i < packet_size; i++) {
107 if (packet[i] != fill_value) {
108 return -1;
112 return fill_value;
115 /* Print information about the ICMPv4 packet we received */
116 void dump_packet_info4(
117 char *packet,
118 int packet_size)
120 int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
121 int pattern;
122 struct IPHeader *ip;
123 struct ICMPHeader *icmp;
124 unsigned char *body;
125 int body_size;
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);
136 if (pattern < 0) {
137 printf("bitpattern none\n");
138 } else {
139 printf("bitpattern %d\n", pattern);
143 /* Print information about an ICMPv6 packet */
144 void dump_packet_info6(
145 char *packet,
146 int packet_size)
148 int pattern;
149 struct ICMPHeader *icmp;
150 unsigned char *body;
151 int body_size;
152 int total_size;
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);
162 if (pattern < 0) {
163 printf("bitpattern none\n");
164 } else {
165 printf("bitpattern %d\n", pattern);
169 /* Receive ICMP packets until we get one intended for this test process */
170 void loop_on_receive(
171 int icmp_socket,
172 int ip_version)
174 int packet_size;
175 char packet[MAX_PACKET_SIZE];
177 while (true) {
178 packet_size = recv(icmp_socket, packet, MAX_PACKET_SIZE, 0);
179 if (packet_size < -1) {
180 perror("Failure during receive");
181 exit(EXIT_FAILURE);
184 if (ip_version == 6) {
185 if (is_packet_for_us6(packet, packet_size)) {
186 dump_packet_info6(packet, packet_size);
187 return;
189 } else {
190 if (is_packet_for_us4(packet, packet_size)) {
191 dump_packet_info4(packet, packet_size);
192 return;
198 /* Parse the commandline arguments */
199 void parse_cmdline(
200 int argc,
201 char **argv,
202 int *ip_version)
204 int opt;
206 *ip_version = 4;
208 while ((opt = getopt(argc, argv, "46")) != -1) {
209 if (opt == '4') {
210 *ip_version = 4;
213 if (opt == '6') {
214 *ip_version = 6;
220 A helper for mtr-packet testing which waits for an ICMP packet
221 intended for this test process, and then prints information about
224 int main(
225 int argc,
226 char **argv)
228 int icmp_socket;
229 int ip_version;
231 parse_cmdline(argc, argv, &ip_version);
233 if (ip_version == 6) {
234 icmp_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
235 } else {
236 icmp_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
238 if (icmp_socket < 0) {
239 perror("Failure opening listening socket");
240 exit(EXIT_FAILURE);
243 printf("status listening\n");
244 fflush(stdout);
246 loop_on_receive(icmp_socket, ip_version);
248 return EXIT_SUCCESS;