Skip to content

Commit 2ff8de3

Browse files
committedDec 25, 2016
mtr-packet: drop capabilities + using BSD's linked lists for probes
At startup, we now use cap_set_proc to drop all privileged capabilities for the mtr-packet process. This means that capabilities granted through the commandline setcap to the mtr-packet executable will only be in effect while the necessary raw sockets are opened, and will be dropped before any command requests are read. Now we use BSD's queue.h linked list support for storing outstanding probes. This makes iterating through in-flight probes more efficient, as we don't need to loop through many unused probe entires when only a few probes are outstanding. Changed mtr-packet's default probe size to 64 bytes, to match mainline mtr's default. The code consistently uses 'exit(EXIT_FAILURE)' instead of 'exit(1)'. The effect is the same, but the intent is clearer.
1 parent 5f76aff commit 2ff8de3

18 files changed

+947
-134
lines changed
 

‎BSDCOPYING

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Portions of this software have the following copyright.
2+
3+
--
4+
5+
Copyright (c) 1991, 1993
6+
The Regents of the University of California. All rights reserved.
7+
8+
Redistribution and use in source and binary forms, with or without
9+
modification, are permitted provided that the following conditions
10+
are met:
11+
1. Redistributions of source code must retain the above copyright
12+
notice, this list of conditions and the following disclaimer.
13+
2. Redistributions in binary form must reproduce the above copyright
14+
notice, this list of conditions and the following disclaimer in the
15+
documentation and/or other materials provided with the distribution.
16+
4. Neither the name of the University nor the names of its contributors
17+
may be used to endorse or promote products derived from this software
18+
without specific prior written permission.
19+
20+
THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21+
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23+
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26+
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27+
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28+
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29+
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30+
SUCH DAMAGE.

‎Makefile.am

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
EXTRA_DIST = \
2+
BSDCOPYING \
23
SECURITY \
34
mtr.bat \
45
img/mtr_icon.xpm
@@ -97,18 +98,21 @@ mtr_packet_SOURCES = \
9798
packet/timeval.c packet/timeval.h \
9899
packet/wait.h
99100

101+
mtr_packet_LDADD = $(CAP_LIBS)
102+
100103

101104
if CYGWIN
102105

103106
mtr_packet_SOURCES += \
104107
packet/command_cygwin.c packet/command_cygwin.h \
105108
packet/probe_cygwin.c packet/probe_cygwin.h \
106109
packet/wait_cygwin.c
107-
mtr_packet_LDADD = -lcygwin -liphlpapi -lws2_32
110+
mtr_packet_LDADD += -lcygwin -liphlpapi -lws2_32
108111

109112
dist_windows_aux = \
110113
$(srcdir)/mtr.bat \
111114
$(srcdir)/AUTHORS \
115+
$(srcdir)/BSDCOPYING \
112116
$(srcdir)/COPYING \
113117
$(srcdir)/README \
114118
$(srcdir)/NEWS

‎SECURITY

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ justified. mtr-packet does the following two things after it is launched:
4444
ICMP packets.
4545
* mtr-packet drops root privileges by setting the effective uid to
4646
match uid or the user calling mtr.
47+
* If capabilities support is availabe, mtr-packet drops all privileged
48+
capabilities.
4749

4850
See main() in packet.c and init_net_state_privileged() in probe_unix.c
4951
for the details of this process.

‎configure.ac

+4
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,10 @@ AS_IF([test "x$with_ncurses" = "xyes"],
108108
])
109109
AM_CONDITIONAL([WITH_NCURSES], [test "x$with_ncurses" = xyes])
110110

111+
AC_CHECK_LIB([cap], [cap_set_proc], [],
112+
AS_IF([test "$host_os" = linux-gnu],
113+
AC_MSG_WARN([Capabilities support is strongly recommended for increased security. See SECURITY for more information.])))
114+
111115
# Enable ipinfo
112116
AC_ARG_WITH([ipinfo],
113117
[AS_HELP_STRING([--without-ipinfo], [Do not try to use ipinfo lookup at all])],

‎packet/command.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ void send_probe_command(
278278
param.command_token = command->token;
279279
param.protocol = IPPROTO_ICMP;
280280
param.ttl = 255;
281-
param.packet_size = 128;
281+
param.packet_size = 64;
282282
param.timeout = 10;
283283

284284
for (i = 0; i < command->argument_count; i++) {

‎packet/command_cygwin.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ void CALLBACK finish_read_command(
4848
}
4949

5050
fprintf(stderr, "ReadFileEx completion failure %d\n", status);
51-
exit(1);
51+
exit(EXIT_FAILURE);
5252
}
5353

5454
/* Copy from the overlapped I/O buffer to the incoming command buffer */
@@ -77,7 +77,7 @@ void queue_empty_apc(void)
7777
if (QueueUserAPC((PAPCFUNC)empty_apc, GetCurrentThread(), 0) == 0) {
7878
fprintf(
7979
stderr, "Unexpected QueueUserAPC failure %d\n", GetLastError());
80-
exit(1);
80+
exit(EXIT_FAILURE);
8181
}
8282
}
8383

@@ -115,7 +115,7 @@ void start_read_command(
115115
} else if (err != WAIT_IO_COMPLETION) {
116116
fprintf(
117117
stderr, "Unexpected ReadFileEx failure %d\n", GetLastError());
118-
exit(1);
118+
exit(EXIT_FAILURE);
119119
}
120120
}
121121

‎packet/command_unix.c

+3-3
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,13 @@ void init_command_buffer(
4242
flags = fcntl(command_stream, F_GETFL, 0);
4343
if (flags == -1) {
4444
perror("Unexpected command stream error");
45-
exit(1);
45+
exit(EXIT_FAILURE);
4646
}
4747

4848
/* Set the O_NONBLOCK bit */
4949
if (fcntl(command_stream, F_SETFL, flags | O_NONBLOCK)) {
5050
perror("Unexpected command stream error");
51-
exit(1);
51+
exit(EXIT_FAILURE);
5252
}
5353
}
5454

@@ -82,7 +82,7 @@ int read_commands(
8282
/* EINTR indicates we received a signal during read */
8383
if (errno != EINTR && errno != EAGAIN) {
8484
perror("Unexpected command buffer read error");
85-
exit(1);
85+
exit(EXIT_FAILURE);
8686
}
8787
}
8888

‎packet/deconstruct_unix.c

+4-2
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,8 @@ void find_and_receive_probe(
5050
}
5151

5252
receive_probe(
53-
probe, icmp_type, remote_addr, timestamp, mpls_count, mpls);
53+
net_state, probe, icmp_type,
54+
remote_addr, timestamp, mpls_count, mpls);
5455
}
5556

5657
/*
@@ -82,7 +83,8 @@ void handle_inner_udp_packet(
8283

8384
if (probe != NULL) {
8485
receive_probe(
85-
probe, icmp_result, remote_addr, timestamp, mpls_count, mpls);
86+
net_state, probe, icmp_result,
87+
remote_addr, timestamp, mpls_count, mpls);
8688
}
8789
}
8890

‎packet/packet.c

+40-5
Original file line numberDiff line numberDiff line change
@@ -16,23 +16,55 @@
1616
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1717
*/
1818

19+
#include "config.h"
20+
1921
#include <errno.h>
2022
#include <stdio.h>
23+
#include <stdlib.h>
24+
#include <string.h>
2125
#include <unistd.h>
2226

27+
#ifdef HAVE_LIBCAP
28+
# include <sys/capability.h>
29+
#endif
30+
2331
#include "wait.h"
2432

2533
/* Drop SUID privileges. To be used after accquiring raw sockets. */
2634
static
27-
void drop_suid_permissions(void)
35+
int drop_elevated_permissions(void)
2836
{
37+
#ifdef HAVE_LIBCAP
38+
cap_t cap;
39+
#endif
40+
41+
/* Drop any suid permissions granted */
2942
if (setgid(getgid()) || setuid(getuid())) {
30-
perror("Unable to drop suid permissions");
43+
return -1;
3144
}
3245

3346
if (geteuid() != getuid() || getegid() != getgid()) {
34-
perror("Unable to drop suid permissions");
47+
return -1;
48+
}
49+
50+
/*
51+
Drop all process capabilities.
52+
This will revoke anything granted by a commandline 'setcap'
53+
*/
54+
#ifdef HAVE_LIBCAP
55+
cap = cap_get_proc();
56+
if (cap == NULL) {
57+
return -1;
58+
}
59+
if (cap_clear(cap)) {
60+
return -1;
61+
}
62+
if (cap_set_proc(cap)) {
63+
return -1;
3564
}
65+
#endif
66+
67+
return 0;
3668
}
3769

3870
int main(
@@ -49,7 +81,10 @@ int main(
4981
raw sockets.
5082
*/
5183
init_net_state_privileged(&net_state);
52-
drop_suid_permissions();
84+
if (drop_elevated_permissions()) {
85+
perror("Unable to drop elevated permissions");
86+
exit(EXIT_FAILURE);
87+
}
5388
init_net_state(&net_state);
5489

5590
init_command_buffer(&command_buffer, fileno(stdin));
@@ -93,7 +128,7 @@ int main(
93128
in-flight probes have reported their status.
94129
*/
95130
if (!command_pipe_open) {
96-
if (count_in_flight_probes(&net_state) == 0) {
131+
if (net_state.outstanding_probe_count == 0) {
97132
break;
98133
}
99134
}

‎packet/probe.c

+24-47
Original file line numberDiff line numberDiff line change
@@ -115,57 +115,39 @@ struct probe_t *alloc_probe(
115115
struct net_state_t *net_state,
116116
int token)
117117
{
118-
int i;
119118
struct probe_t *probe;
120119

121-
for (i = 0; i < MAX_PROBES; i++) {
122-
probe = &net_state->probes[i];
120+
if (net_state->outstanding_probe_count >= MAX_PROBES) {
121+
return NULL;
122+
}
123123

124-
if (!probe->used) {
125-
memset(probe, 0, sizeof(struct probe_t));
124+
probe = malloc(sizeof(struct probe_t));
125+
if (probe == NULL) {
126+
return NULL;
127+
}
126128

127-
probe->used = true;
128-
probe->token = token;
129+
memset(probe, 0, sizeof(struct probe_t));
130+
probe->token = token;
129131

130-
platform_alloc_probe(net_state, probe);
132+
platform_alloc_probe(net_state, probe);
131133

132-
return probe;
133-
}
134-
}
134+
net_state->outstanding_probe_count++;
135+
LIST_INSERT_HEAD(&net_state->outstanding_probes, probe, probe_list_entry);
135136

136-
return NULL;
137+
return probe;
137138
}
138139

139140
/* Mark a probe tracking structure as unused */
140141
void free_probe(
142+
struct net_state_t *net_state,
141143
struct probe_t *probe)
142144
{
143-
platform_free_probe(probe);
144-
145-
probe->used = false;
146-
}
147-
148-
/*
149-
Return the number of probes which haven't yet received a reply
150-
and haven't yet timed out.
151-
*/
152-
int count_in_flight_probes(
153-
struct net_state_t *net_state)
154-
{
155-
int i;
156-
int count;
157-
struct probe_t *probe;
145+
LIST_REMOVE(probe, probe_list_entry);
146+
net_state->outstanding_probe_count--;
158147

159-
count = 0;
160-
for (i = 0; i < MAX_PROBES; i++) {
161-
probe = &net_state->probes[i];
162-
163-
if (probe->used) {
164-
count++;
165-
}
166-
}
148+
platform_free_probe(probe);
167149

168-
return count;
150+
free(probe);
169151
}
170152

171153
/*
@@ -178,7 +160,6 @@ struct probe_t *find_probe(
178160
int id,
179161
int sequence)
180162
{
181-
int i;
182163
struct probe_t *probe;
183164

184165
/*
@@ -195,14 +176,9 @@ struct probe_t *find_probe(
195176
}
196177
}
197178

198-
199-
for (i = 0; i < MAX_PROBES; i++) {
200-
probe = &net_state->probes[i];
201-
202-
if (probe->used) {
203-
if (htons(probe->sequence) == sequence) {
204-
return probe;
205-
}
179+
LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
180+
if (htons(probe->sequence) == sequence) {
181+
return probe;
206182
}
207183
}
208184

@@ -251,6 +227,7 @@ void format_mpls_string(
251227
sent the probe.
252228
*/
253229
void respond_to_probe(
230+
struct net_state_t *net_state,
254231
struct probe_t *probe,
255232
int icmp_type,
256233
const struct sockaddr_storage *remote_addr,
@@ -289,7 +266,7 @@ void respond_to_probe(
289266
remote_addr->ss_family, addr, ip_text, IP_TEXT_LENGTH) == NULL) {
290267

291268
perror("inet_ntop failure");
292-
exit(1);
269+
exit(EXIT_FAILURE);
293270
}
294271

295272
snprintf(
@@ -308,7 +285,7 @@ void respond_to_probe(
308285
}
309286

310287
puts(response);
311-
free_probe(probe);
288+
free_probe(net_state, probe);
312289
}
313290

314291
/*

‎packet/probe.h

+14-9
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include <stdbool.h>
2626
#include <sys/time.h>
2727

28+
#include "portability/queue.h"
29+
2830
#ifdef PLATFORM_CYGWIN
2931
#include "probe_cygwin.h"
3032
#else
@@ -82,8 +84,8 @@ struct probe_param_t
8284
/* Tracking information for an outstanding probe */
8385
struct probe_t
8486
{
85-
/* true if this entry is in use */
86-
bool used;
87+
/* Our entry in the probe list */
88+
LIST_ENTRY(probe_t) probe_list_entry;
8789

8890
/*
8991
Also the ICMP sequence ID used to identify the probe.
@@ -106,13 +108,17 @@ struct probe_t
106108
/* Global state for interacting with the network */
107109
struct net_state_t
108110
{
111+
/* The number of entries in the outstanding_probes list */
112+
int outstanding_probe_count;
113+
109114
/* Tracking information for in-flight probes */
110-
struct probe_t probes[MAX_PROBES];
115+
LIST_HEAD(probe_list_head_t, probe_t) outstanding_probes;
111116

112117
/* Platform specific tracking information */
113118
struct net_state_platform_t platform;
114119
};
115120

121+
/* Multiprotocol Label Switching information */
116122
struct mpls_label_t
117123
{
118124
uint32_t label;
@@ -146,6 +152,7 @@ void check_probe_timeouts(
146152
struct net_state_t *net_state);
147153

148154
void respond_to_probe(
155+
struct net_state_t *net_state,
149156
struct probe_t *probe,
150157
int icmp_type,
151158
const struct sockaddr_storage *remote_addr,
@@ -167,19 +174,17 @@ struct probe_t *alloc_probe(
167174
struct net_state_t *net_state,
168175
int token);
169176

170-
void platform_alloc_probe(
177+
void free_probe(
171178
struct net_state_t *net_state,
172179
struct probe_t *probe);
173180

174-
void platform_free_probe(
181+
void platform_alloc_probe(
182+
struct net_state_t *net_state,
175183
struct probe_t *probe);
176184

177-
void free_probe(
185+
void platform_free_probe(
178186
struct probe_t *probe);
179187

180-
int count_in_flight_probes(
181-
struct net_state_t *net_state);
182-
183188
struct probe_t *find_probe(
184189
struct net_state_t *net_state,
185190
int protocol,

‎packet/probe_cygwin.c

+11-8
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,13 @@ void init_net_state(
3838
net_state->platform.icmp4 = IcmpCreateFile();
3939
if (net_state->platform.icmp4 == INVALID_HANDLE_VALUE) {
4040
fprintf(stderr, "Failure opening ICMPv4 %d\n", GetLastError());
41-
exit(1);
41+
exit(EXIT_FAILURE);
4242
}
4343

4444
net_state->platform.icmp6 = Icmp6CreateFile();
4545
if (net_state->platform.icmp6 == INVALID_HANDLE_VALUE) {
4646
fprintf(stderr, "Failure opening ICMPv6 %d\n", GetLastError());
47-
exit(1);
47+
exit(EXIT_FAILURE);
4848
}
4949
}
5050

@@ -60,11 +60,12 @@ bool is_protocol_supported(
6060
return false;
6161
}
6262

63-
/* No special action is required for Cygwin on probe allocation */
63+
/* Set the back pointer to the net_state when a probe is allocated */
6464
void platform_alloc_probe(
6565
struct net_state_t *net_state,
6666
struct probe_t *probe)
6767
{
68+
probe->platform.net_state = net_state;
6869
}
6970

7071
/* Free the reply buffer when the probe is freed */
@@ -112,6 +113,7 @@ void WINAPI on_icmp_reply(
112113
ULONG reserved)
113114
{
114115
struct probe_t *probe = (struct probe_t *)context;
116+
struct net_state_t *net_state = probe->platform.net_state;
115117
int icmp_type;
116118
int round_trip_us = 0;
117119
int reply_count;
@@ -163,7 +165,7 @@ void WINAPI on_icmp_reply(
163165
err = GetLastError();
164166

165167
report_win_error(probe->token, err);
166-
free_probe(probe);
168+
free_probe(net_state, probe);
167169
return;
168170
}
169171

@@ -178,7 +180,8 @@ void WINAPI on_icmp_reply(
178180
if (icmp_type != -1) {
179181
/* Record probe result */
180182
respond_to_probe(
181-
probe, icmp_type, &remote_addr, round_trip_us, 0, NULL);
183+
net_state, probe, icmp_type,
184+
&remote_addr, round_trip_us, 0, NULL);
182185
} else {
183186
fprintf(stderr, "Unexpected ICMP result %d\n", icmp_type);
184187
}
@@ -227,7 +230,7 @@ void icmp_send_probe(
227230
probe->platform.reply4 = malloc(reply_size);
228231
if (probe->platform.reply4 == NULL) {
229232
perror("failure to allocate reply buffer");
230-
exit(1);
233+
exit(EXIT_FAILURE);
231234
}
232235

233236
if (param->ip_version == 6) {
@@ -258,7 +261,7 @@ void icmp_send_probe(
258261
*/
259262
if (err != ERROR_IO_PENDING) {
260263
report_win_error(probe->token, err);
261-
free_probe(probe);
264+
free_probe(net_state, probe);
262265
}
263266
}
264267
}
@@ -324,7 +327,7 @@ void send_probe(
324327
payload_size = fill_payload(param, payload, PACKET_BUFFER_SIZE);
325328
if (payload_size < 0) {
326329
perror("Error construction packet");
327-
exit(1);
330+
exit(EXIT_FAILURE);
328331
}
329332

330333
icmp_send_probe(

‎packet/probe_cygwin.h

+6
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,12 @@ typedef struct icmpv6_echo_reply_lh
5151
*/
5252
struct probe_platform_t
5353
{
54+
/*
55+
We need a backpointer to the net_state because of the way
56+
IcmpSendEcho2 passes our context.
57+
*/
58+
struct net_state_t *net_state;
59+
5460
/* IP version (4 or 6) used for the probe */
5561
int ip_version;
5662

‎packet/probe_unix.c

+44-53
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ void check_length_order(
9999

100100
if (resolve_probe_addresses(&param, &dest_sockaddr, &src_sockaddr)) {
101101
fprintf(stderr, "Error decoding localhost address\n");
102-
exit(1);
102+
exit(EXIT_FAILURE);
103103
}
104104

105105
/* First attempt to ping the localhost with network byte order */
@@ -111,7 +111,7 @@ void check_length_order(
111111
&dest_sockaddr, &src_sockaddr, &param);
112112
if (packet_size < 0) {
113113
perror("Unable to send to localhost");
114-
exit(1);
114+
exit(EXIT_FAILURE);
115115
}
116116

117117
bytes_sent = send_packet(
@@ -129,14 +129,14 @@ void check_length_order(
129129
&dest_sockaddr, &src_sockaddr, &param);
130130
if (packet_size < 0) {
131131
perror("Unable to send to localhost");
132-
exit(1);
132+
exit(EXIT_FAILURE);
133133
}
134134

135135
bytes_sent = send_packet(
136136
net_state, &param, packet, packet_size, &dest_sockaddr);
137137
if (bytes_sent < 0) {
138138
perror("Unable to send with swapped length");
139-
exit(1);
139+
exit(EXIT_FAILURE);
140140
}
141141
}
142142

@@ -171,12 +171,12 @@ void set_socket_nonblocking(
171171
flags = fcntl(socket, F_GETFL, 0);
172172
if (flags == -1) {
173173
perror("Unexpected socket F_GETFL error");
174-
exit(1);
174+
exit(EXIT_FAILURE);
175175
}
176176

177177
if (fcntl(socket, F_SETFL, flags | O_NONBLOCK)) {
178178
perror("Unexpected socket F_SETFL O_NONBLOCK error");
179-
exit(1);
179+
exit(EXIT_FAILURE);
180180
}
181181
}
182182

@@ -192,7 +192,7 @@ void open_ip4_sockets(
192192
send_socket = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);
193193
if (send_socket == -1) {
194194
perror("Failure opening IPv4 send socket");
195-
exit(1);
195+
exit(EXIT_FAILURE);
196196
}
197197

198198
/*
@@ -203,7 +203,7 @@ void open_ip4_sockets(
203203
send_socket, IPPROTO_IP, IP_HDRINCL, &trueopt, sizeof(int))) {
204204

205205
perror("Failure to set IP_HDRINCL");
206-
exit(1);
206+
exit(EXIT_FAILURE);
207207
}
208208

209209
/*
@@ -213,7 +213,7 @@ void open_ip4_sockets(
213213
recv_socket = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
214214
if (recv_socket == -1) {
215215
perror("Failure opening IPv4 receive socket");
216-
exit(1);
216+
exit(EXIT_FAILURE);
217217
}
218218

219219
net_state->platform.ip4_send_socket = send_socket;
@@ -232,19 +232,19 @@ void open_ip6_sockets(
232232
send_socket_icmp = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
233233
if (send_socket_icmp == -1) {
234234
perror("Failure opening ICMPv6 send socket");
235-
exit(1);
235+
exit(EXIT_FAILURE);
236236
}
237237

238238
send_socket_udp = socket(AF_INET6, SOCK_RAW, IPPROTO_UDP);
239239
if (send_socket_udp == -1) {
240240
perror("Failure opening UDPv6 send socket");
241-
exit(1);
241+
exit(EXIT_FAILURE);
242242
}
243243

244244
recv_socket = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
245245
if (recv_socket == -1) {
246246
perror("Failure opening IPv6 receive socket");
247-
exit(1);
247+
exit(EXIT_FAILURE);
248248
}
249249

250250
set_socket_nonblocking(recv_socket);
@@ -352,13 +352,13 @@ void send_probe(
352352

353353
if (resolve_probe_addresses(param, &probe->remote_addr, &src_sockaddr)) {
354354
printf("%d invalid-argument\n", param->command_token);
355-
free_probe(probe);
355+
free_probe(net_state, probe);
356356
return;
357357
}
358358

359359
if (gettimeofday(&probe->platform.departure_time, NULL)) {
360360
perror("gettimeofday failure");
361-
exit(1);
361+
exit(EXIT_FAILURE);
362362
}
363363

364364
packet_size = construct_packet(
@@ -375,10 +375,11 @@ void send_probe(
375375
*/
376376
if (errno == ECONNREFUSED) {
377377
receive_probe(
378-
probe, ICMP_ECHOREPLY, &probe->remote_addr, NULL, 0, NULL);
378+
net_state, probe, ICMP_ECHOREPLY,
379+
&probe->remote_addr, NULL, 0, NULL);
379380
} else {
380381
report_packet_error(param->command_token);
381-
free_probe(probe);
382+
free_probe(net_state, probe);
382383
}
383384

384385
return;
@@ -390,7 +391,7 @@ void send_probe(
390391
packet, packet_size, &probe->remote_addr) == -1) {
391392

392393
report_packet_error(param->command_token);
393-
free_probe(probe);
394+
free_probe(net_state, probe);
394395
return;
395396
}
396397
}
@@ -429,6 +430,7 @@ void platform_free_probe(
429430
to the platform agnostic response handling.
430431
*/
431432
void receive_probe(
433+
struct net_state_t *net_state,
432434
struct probe_t *probe,
433435
int icmp_type,
434436
const struct sockaddr_storage *remote_addr,
@@ -443,7 +445,7 @@ void receive_probe(
443445
if (timestamp == NULL) {
444446
if (gettimeofday(&now, NULL)) {
445447
perror("gettimeofday failure");
446-
exit(1);
448+
exit(EXIT_FAILURE);
447449
}
448450

449451
timestamp = &now;
@@ -454,7 +456,8 @@ void receive_probe(
454456
timestamp->tv_usec - departure_time->tv_usec;
455457

456458
respond_to_probe(
457-
probe, icmp_type, remote_addr, round_trip_us, mpls_count, mpls);
459+
net_state, probe, icmp_type,
460+
remote_addr, round_trip_us, mpls_count, mpls);
458461
}
459462

460463
/*
@@ -486,7 +489,7 @@ void receive_replies_from_icmp_socket(
486489
*/
487490
if (gettimeofday(&timestamp, NULL)) {
488491
perror("gettimeofday failure");
489-
exit(1);
492+
exit(EXIT_FAILURE);
490493
}
491494

492495
if (packet_length == -1) {
@@ -507,7 +510,7 @@ void receive_replies_from_icmp_socket(
507510
}
508511

509512
perror("Failure receiving replies");
510-
exit(1);
513+
exit(EXIT_FAILURE);
511514
}
512515

513516
handle_received_packet(
@@ -547,7 +550,7 @@ void receive_replies_from_probe_socket(
547550
return;
548551
} else {
549552
perror("probe socket select error");
550-
exit(1);
553+
exit(EXIT_FAILURE);
551554
}
552555
}
553556

@@ -560,7 +563,7 @@ void receive_replies_from_probe_socket(
560563

561564
if (getsockopt(probe_socket, SOL_SOCKET, SO_ERROR, &err, &err_length)) {
562565
perror("probe socket SO_ERROR");
563-
exit(1);
566+
exit(EXIT_FAILURE);
564567
}
565568

566569
/*
@@ -569,20 +572,21 @@ void receive_replies_from_probe_socket(
569572
*/
570573
if (!err || err == ECONNREFUSED) {
571574
receive_probe(
572-
probe, ICMP_ECHOREPLY, &probe->remote_addr, NULL, 0, NULL);
575+
net_state, probe, ICMP_ECHOREPLY,
576+
&probe->remote_addr, NULL, 0, NULL);
573577
} else {
574578
errno = err;
575579
report_packet_error(probe->token);
576-
free_probe(probe);
580+
free_probe(net_state, probe);
577581
}
578582
}
579583

580584
/* Check both the IPv4 and IPv6 sockets for incoming packets */
581585
void receive_replies(
582586
struct net_state_t *net_state)
583587
{
584-
int i;
585588
struct probe_t *probe;
589+
struct probe_t *probe_safe_iter;
586590

587591
receive_replies_from_icmp_socket(
588592
net_state, net_state->platform.ip4_recv_socket,
@@ -592,12 +596,11 @@ void receive_replies(
592596
net_state, net_state->platform.ip6_recv_socket,
593597
handle_received_ip6_packet);
594598

595-
for (i = 0; i < MAX_PROBES; i++) {
596-
probe = &net_state->probes[i];
599+
LIST_FOREACH_SAFE(
600+
probe, &net_state->outstanding_probes,
601+
probe_list_entry, probe_safe_iter) {
597602

598-
if (probe->used) {
599-
receive_replies_from_probe_socket(net_state, probe);
600-
}
603+
receive_replies_from_probe_socket(net_state, probe);
601604
}
602605
}
603606

@@ -609,18 +612,16 @@ int gather_probe_sockets(
609612
const struct net_state_t *net_state,
610613
fd_set *write_set)
611614
{
612-
int i;
613615
int probe_socket;
614616
int nfds;
615617
const struct probe_t *probe;
616618

617619
nfds = 0;
618620

619-
for (i = 0; i < MAX_PROBES; i++) {
620-
probe = &net_state->probes[i];
621+
LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
621622
probe_socket = probe->platform.socket;
622623

623-
if (probe->used && probe_socket) {
624+
if (probe_socket) {
624625
FD_SET(probe_socket, write_set);
625626
if (probe_socket >= nfds) {
626627
nfds = probe_socket + 1;
@@ -641,26 +642,22 @@ void check_probe_timeouts(
641642
{
642643
struct timeval now;
643644
struct probe_t *probe;
644-
int i;
645+
struct probe_t *probe_safe_iter;
645646

646647
if (gettimeofday(&now, NULL)) {
647648
perror("gettimeofday failure");
648-
exit(1);
649+
exit(EXIT_FAILURE);
649650
}
650651

651-
for (i = 0; i < MAX_PROBES; i++) {
652-
probe = &net_state->probes[i];
653-
654-
/* Don't check probes which aren't currently outstanding */
655-
if (!probe->used) {
656-
continue;
657-
}
652+
LIST_FOREACH_SAFE(
653+
probe, &net_state->outstanding_probes,
654+
probe_list_entry, probe_safe_iter) {
658655

659656
if (compare_timeval(probe->platform.timeout_time, now) < 0) {
660657
/* Report timeout to the command stream */
661658
printf("%d no-reply\n", probe->token);
662659

663-
free_probe(probe);
660+
free_probe(net_state, probe);
664661
}
665662
}
666663
}
@@ -677,24 +674,18 @@ bool get_next_probe_timeout(
677674
const struct net_state_t *net_state,
678675
struct timeval *timeout)
679676
{
680-
int i;
681677
bool have_timeout;
682678
const struct probe_t *probe;
683679
struct timeval now;
684680
struct timeval probe_timeout;
685681

686682
if (gettimeofday(&now, NULL)) {
687683
perror("gettimeofday failure");
688-
exit(1);
684+
exit(EXIT_FAILURE);
689685
}
690686

691687
have_timeout = false;
692-
for (i = 0; i < MAX_PROBES; i++) {
693-
probe = &net_state->probes[i];
694-
if (!probe->used) {
695-
continue;
696-
}
697-
688+
LIST_FOREACH(probe, &net_state->outstanding_probes, probe_list_entry) {
698689
probe_timeout.tv_sec =
699690
probe->platform.timeout_time.tv_sec - now.tv_sec;
700691
probe_timeout.tv_usec =

‎packet/probe_unix.h

+1
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ void set_socket_nonblocking(
7575
int socket);
7676

7777
void receive_probe(
78+
struct net_state_t *net_state,
7879
struct probe_t *probe,
7980
int icmp_type,
8081
const struct sockaddr_storage *remote_addr,

‎packet/wait_cygwin.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,6 @@ void wait_for_activity(
5050

5151
if (wait_result == WAIT_FAILED) {
5252
fprintf(stderr, "SleepEx failure %d\n", GetLastError());
53-
exit(1);
53+
exit(EXIT_FAILURE);
5454
}
5555
}

‎packet/wait_unix.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ void wait_for_activity(
115115
if (errno != EINTR && errno != EAGAIN) {
116116
/* We don't expect other errors, so report them */
117117
perror("unexpected select error");
118-
exit(1);
118+
exit(EXIT_FAILURE);
119119
}
120120
}
121121
}

‎portability/queue.h

+753
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)
Please sign in to comment.