Annotation of embedaddon/mtr/test/packet_listen.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 <netinet/in.h>
20: #include <stdbool.h>
21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <sys/socket.h>
24: #include <unistd.h>
25:
26: #include "packet/protocols.h"
27:
28: #define MAX_PACKET_SIZE 9000
29:
30: /*
31: The first probe sent by mtr-packet will have this sequence number,
32: so wait for an ICMP packet with this sequence ID.
33: */
34: #define SEQUENCE_NUM 33000
35:
36: /*
37: Check to see if the packet we've recieved is intended for this test
38: process. We expected the ICMP sequence number to be equal to our
39: process ID.
40: */
41: bool is_packet_for_us4(
42: char *packet,
43: int packet_size)
44: {
45: int ip_icmp_size = sizeof(struct IPHeader) + sizeof(struct ICMPHeader);
46: int expected_sequence;
47: struct IPHeader *ip;
48: struct ICMPHeader *icmp;
49:
50: if (packet_size < ip_icmp_size) {
51: return false;
52: }
53:
54: ip = (struct IPHeader *)packet;
55: icmp = (struct ICMPHeader *)(ip + 1);
56:
57: expected_sequence = htons(SEQUENCE_NUM);
58: if (icmp->sequence == expected_sequence) {
59: return true;
60: }
61:
62: return false;
63: }
64:
65: /*
66: Check to see if the ICMPv6 packet is for us.
67: Unlike ICMPv4 packets, ICMPv6 packets don't include the IP header.
68: */
69: bool is_packet_for_us6(
70: char *packet,
71: int packet_size)
72: {
73: int expected_sequence;
74: struct ICMPHeader *icmp;
75:
76: if (packet_size < sizeof(struct ICMPHeader)) {
77: return false;
78: }
79:
80: icmp = (struct ICMPHeader *)packet;
81:
82: expected_sequence = htons(SEQUENCE_NUM);
83: if (icmp->sequence == expected_sequence) {
84: return true;
85: }
86:
87: return false;
88: }
89:
90: /*
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.
93: */
94: int get_packet_pattern(
95: unsigned char *packet,
96: int packet_size)
97: {
98: int fill_value;
99: int i;
100:
101: if (packet_size <= 0) {
102: return -1;
103: }
104:
105: fill_value = packet[0];
106: for (i = 1; i < packet_size; i++) {
107: if (packet[i] != fill_value) {
108: return -1;
109: }
110: }
111:
112: return fill_value;
113: }
114:
115: /* Print information about the ICMPv4 packet we received */
116: void dump_packet_info4(
117: char *packet,
118: int packet_size)
119: {
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;
126:
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;
131:
132: printf("size %d\n", packet_size);
133: printf("tos %d\n", ip->tos);
134:
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);
140: }
141: }
142:
143: /* Print information about an ICMPv6 packet */
144: void dump_packet_info6(
145: char *packet,
146: int packet_size)
147: {
148: int pattern;
149: struct ICMPHeader *icmp;
150: unsigned char *body;
151: int body_size;
152: int total_size;
153:
154: icmp = (struct ICMPHeader *)packet;
155: body = (unsigned char *)(icmp + 1);
156: body_size = packet_size - sizeof(struct ICMPHeader);
157:
158: total_size = packet_size + sizeof(struct IP6Header);
159: printf("size %d\n", total_size);
160:
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);
166: }
167: }
168:
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)
173: {
174: int packet_size;
175: char packet[MAX_PACKET_SIZE];
176:
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);
182: }
183:
184: if (ip_version == 6) {
185: if (is_packet_for_us6(packet, packet_size)) {
186: dump_packet_info6(packet, packet_size);
187: return;
188: }
189: } else {
190: if (is_packet_for_us4(packet, packet_size)) {
191: dump_packet_info4(packet, packet_size);
192: return;
193: }
194: }
195: }
196: }
197:
198: /* Parse the commandline arguments */
199: void parse_cmdline(
200: int argc,
201: char **argv,
202: int *ip_version)
203: {
204: int opt;
205:
206: *ip_version = 4;
207:
208: while ((opt = getopt(argc, argv, "46")) != -1) {
209: if (opt == '4') {
210: *ip_version = 4;
211: }
212:
213: if (opt == '6') {
214: *ip_version = 6;
215: }
216: }
217: }
218:
219: /*
220: A helper for mtr-packet testing which waits for an ICMP packet
221: intended for this test process, and then prints information about
222: it.
223: */
224: int main(
225: int argc,
226: char **argv)
227: {
228: int icmp_socket;
229: int ip_version;
230:
231: parse_cmdline(argc, argv, &ip_version);
232:
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);
237: }
238: if (icmp_socket < 0) {
239: perror("Failure opening listening socket");
240: exit(EXIT_FAILURE);
241: }
242:
243: printf("status listening\n");
244: fflush(stdout);
245:
246: loop_on_receive(icmp_socket, ip_version);
247:
248: return EXIT_SUCCESS;
249: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>