-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathping_io.c
218 lines (187 loc) · 7.56 KB
/
ping_io.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
#include "ping.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <sys/time.h>
extern ping_context_t ping_ctx;
static void print_iphdr(struct iphdr *ip)
{
char ip_buffer[64] = { 0 };
printf("Vr HL TOS Len ID Flg off TTL Pro cks Src Dst\n");
printf(" %1x %1x %02x %04x %04x",
ip->version, ip->ihl, ip->tos, ip->tot_len, ip->id);
printf(" %1x %04x", ((ip->frag_off) & 0xe000) >> 13,
(ip->frag_off) & 0x1fff);
printf(" %02x %02x %04x", ip->ttl, ip->protocol, ip->check);
inet_ntop(AF_INET, (struct in_addr *)&ip->saddr, ip_buffer, sizeof ip_buffer);
printf(" %s ", ip_buffer);
inet_ntop(AF_INET, (struct in_addr *)&ip->daddr, ip_buffer, sizeof ip_buffer);
printf(" %s ", ip_buffer);
printf("\n\n");
}
void sync_ping() {
char ip_buffer[64] = {0};
inet_ntop(AF_INET, &ping_ctx.dest_addr, ip_buffer, sizeof ip_buffer);
printf("PING %s (%s) %d(%lu) bytes of data.\n", ping_ctx.canon_dest,
ip_buffer,
ping_ctx.payload_size,
ping_ctx.payload_size + icmp_hdr_size + ip_hdr_size);
while (true) {
if (send_icmp_msg_v4(
ping_ctx.icmp_sock,
getpid(),
ping_ctx.ttl,
ICMP_ECHO,
ping_ctx.messages_sent + 1,
ping_ctx.payload_size,
ping_ctx.src_addr,
ping_ctx.dest_addr
) != 0) {
perror("cannot send echo");
exit(EXIT_FAILURE);
}
ping_ctx.messages_sent++;
if (ping_ctx.interval_between_echoes == 0) {
usleep(MINIMUM_WAIT_MICROSECONDS);
}
else {
sleep(ping_ctx.interval_between_echoes);
}
}
}
void sync_pong() {
char output[1024], ip_buffer[64], host_name[NI_MAXHOST], buffer[2048];
struct timeval current_time, send_time;
struct iovec iov[1];
struct msghdr msg;
ssize_t ret;
// Init message struct
memset(&msg, 0, sizeof(msg));
memset(iov, 0, sizeof(iov));
iov[0].iov_base = buffer;
iov[0].iov_len = sizeof buffer;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
while (true) {
// Read input stream...
ret = recvmsg(ping_ctx.icmp_sock, &msg, 0);
// Handle errors
if (ret < 0) {
perror("Holy shit!");
exit(EXIT_FAILURE);
}
else if (ret == 0) {
perror("Connection closed");
}
if ((size_t)ret < ip_hdr_size + icmp_hdr_size) {
fprintf(stderr, "Something impossible happened,"
"packet is too small, ignoring\n");
continue;
}
// Get current time for different needs
if (gettimeofday(¤t_time, NULL) != 0) {
perror("cannot get time");
exit(EXIT_FAILURE);
}
// Struct pointers
struct ip* ip_hdr = (struct ip*)buffer;
struct icmp *icmp_hdr = (struct icmp*)(buffer + ip_hdr_size);
// Ignore messages which are not for us
if (ip_hdr->ip_dst.s_addr != ping_ctx.src_addr) {
continue;
}
// Clear output print buffer...
memset(output, 0, sizeof output);
// Timestamp if needed
if (ping_ctx.flags[PING_TIMESTAMP_PREF]) {
sprintf(output + strlen(output), "[%zu.%06zu] ", current_time.tv_sec, current_time.tv_usec);
}
// Parse response msg
in_addr_t sender_ip = ip_hdr->ip_src.s_addr;
if (icmp_hdr->icmp_type == ICMP_ECHOREPLY) {
// Good echo-reply received
ping_ctx.messages_received++;
sprintf(output + strlen(output), "%ld bytes ",
ntohs(ip_hdr->ip_len) - sizeof (struct iphdr));
inet_ntop(AF_INET, &sender_ip, ip_buffer, sizeof ip_buffer);
if (ping_ctx.flags[PING_NO_DNS_NAME]) {
// Print out without DNS name
sprintf(output + strlen(output), "from %s: ", ip_buffer);
}
else if (!ping_ctx.flags[PING_QUIET]){
if (get_name_by_ipaddr(sender_ip, host_name, sizeof host_name) != 0) {
perror("cannot resolve ip");
exit(EXIT_FAILURE);
}
sprintf(output + strlen(output), "from %s (%s): ", host_name, ip_buffer);
}
sprintf(output + strlen(output), "icmp_seq=%d ", ntohs(icmp_hdr->icmp_seq));
sprintf(output + strlen(output), "ttl=%d ", ip_hdr->ip_ttl);
if (ret - ip_hdr_size - icmp_hdr_size >= sizeof (struct timeval)) {
// There is timestamp? Using it!
char *icmp_payload_ptr = buffer + ip_hdr_size + icmp_hdr_size;
memcpy(&send_time, icmp_payload_ptr, sizeof send_time);
const uint64_t trip_time = time_diff(&send_time, ¤t_time);
ping_ctx.min_ping_time = min(ping_ctx.min_ping_time, trip_time);
ping_ctx.max_ping_time = max(ping_ctx.max_ping_time, trip_time);
ping_ctx.acc_ping_time += trip_time;
ping_ctx.acc_ping_time2 += (trip_time * trip_time);
ping_ctx.stats_count++;
sprintf(output + strlen(output), "time=%ld.%02ld ms",
trip_time / 1000, trip_time % 1000 / 10);
}
// Put ASCII 0x07 when good packet received
if (ping_ctx.flags[PING_AUDIBLE]) {
printf("%c", '\a');
fflush(stdout);
}
}
else {
// Bad echo reply received
ping_ctx.error_messages_received++;
inet_ntop(AF_INET, &sender_ip, ip_buffer, sizeof ip_buffer);
if (ping_ctx.flags[PING_NO_DNS_NAME]) {
// Print out without DNS name
sprintf(output + strlen(output), "From %s ", ip_buffer);
}
else if (!ping_ctx.flags[PING_QUIET]) {
if (get_name_by_ipaddr(sender_ip, host_name, sizeof host_name) != 0) {
perror("cannot resolve ip");
exit(EXIT_FAILURE);
}
sprintf(output + strlen(output), "From %s (%s) ", host_name, ip_buffer);
}
sprintf(output + strlen(output), "icmp_seq=%d ",
/* on error icmp_seq number is in the last 2 bytes of payload */
ntohs(*(uint16_t*)&buffer[ret - 2]));
// Append error
if (icmp_hdr->icmp_type == ICMP_TIME_EXCEEDED)
sprintf(output + strlen(output), "Time to live exceeded");
else if (icmp_hdr->icmp_type == ICMP_DEST_UNREACH)
sprintf(output + strlen(output), "Destination Unreachable");
else
sprintf(output + strlen(output), "Unknown ICMP return code: %x", icmp_hdr->icmp_type);
}
if (!ping_ctx.flags[PING_QUIET]) {
printf("%s\n", output);
}
if (ping_ctx.flags[PING_VERBOSE] && icmp_hdr->icmp_type != ICMP_ECHOREPLY) {
print_iphdr((struct iphdr*)ip_hdr);
}
// End job if needed
if (ping_ctx.flags[PING_RESPONSE_LIM]
&& ping_ctx.messages_received + ping_ctx.error_messages_received == ping_ctx.response_count_limit) {
raise(SIGINT);
}
}
}
__suseconds_t time_diff(struct timeval* begin, struct timeval *end) {
__suseconds_t ret;
ret = end->tv_sec - begin->tv_sec;
ret *= MICROSECONDS_IN_SECOND;
ret += (end->tv_usec - begin->tv_usec);
return ret;
}