Skip to content

Commit a237394

Browse files
committed
handle long input lines when reading from file
This addresses GitHub isse #377. Before, input lines longer than the static buffer used to read data would be handled as if each buffer part were one line. This could result in splitting input target names into multiple different target names. Since the static buffer was significantly smaller then the maximum length of DNS names (just short of 255 one octet characters), valid long DNS names could not be read as targets via file. This commit fixes the splitting of long lines, and also increases the maximum length of target names to 255 one octet characters. The additional line parsing code is kept similar to the existing code and attempts to keep all intended and/or useful features to minimize the risk of regressions.
1 parent c362b00 commit a237394

File tree

4 files changed

+404
-8
lines changed

4 files changed

+404
-8
lines changed

CHANGELOG.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,12 @@ Next
33

44
## Bugfixes and other changes
55

6-
- Fix fallback to SO\_TIMESTAMP if SO\_TIMESTAMPNS is not available (#375, thanks
7-
@auerswal)
6+
- Fix fallback to SO\_TIMESTAMP if SO\_TIMESTAMPNS is not available (#375,
7+
thanks @auerswal)
8+
9+
- When reading target names from file or standard input, lines longer
10+
than the static buffer are no longer interpreted as more than one line
11+
(#378, thanks @auerswal)
812

913
## New features
1014

ci/test-issue-377.pl

Lines changed: 328 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,328 @@
1+
#!/usr/bin/perl -w
2+
3+
# regression testing for github issue #377
4+
# (lines longer than the fixed buffer were split into multiple lines)
5+
6+
use Test::Command tests => 66;
7+
use File::Temp;
8+
9+
{
10+
# the issue was noticed with a very long target name (too long for DNS)
11+
my $tmpfile = File::Temp->new();
12+
print $tmpfile "a"x300 .".invalid\n";
13+
close($tmpfile);
14+
15+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
16+
$cmd->exit_is_num(1);
17+
$cmd->stdout_is_eq("");
18+
$cmd->stderr_is_eq("fping: target name too long\n");
19+
}
20+
21+
{
22+
# the issue was noticed with a very long target name (too long for DNS)
23+
# (no newline)
24+
my $tmpfile = File::Temp->new();
25+
print $tmpfile "a"x300 .".invalid";
26+
close($tmpfile);
27+
28+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
29+
$cmd->exit_is_num(1);
30+
$cmd->stdout_is_eq("");
31+
$cmd->stderr_is_eq("fping: target name too long\n");
32+
}
33+
34+
{
35+
# a too long word can be found in two consecutive parts of the line
36+
my $tmpfile = File::Temp->new();
37+
print $tmpfile " "x200 ."a"x300 .".invalid\n";
38+
close($tmpfile);
39+
40+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
41+
$cmd->exit_is_num(1);
42+
$cmd->stdout_is_eq("");
43+
$cmd->stderr_is_eq("fping: target name too long\n");
44+
}
45+
46+
{
47+
# a too long word can be found in two consecutive parts of the line
48+
# (no newline)
49+
my $tmpfile = File::Temp->new();
50+
print $tmpfile " "x200 ."a"x300 .".invalid";
51+
close($tmpfile);
52+
53+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
54+
$cmd->exit_is_num(1);
55+
$cmd->stdout_is_eq("");
56+
$cmd->stderr_is_eq("fping: target name too long\n");
57+
}
58+
59+
{
60+
# a too long word starting with the second part of the line (256B buffer)
61+
my $tmpfile = File::Temp->new();
62+
print $tmpfile " "x255 ."a"x300 .".invalid\n";
63+
close($tmpfile);
64+
65+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
66+
$cmd->exit_is_num(1);
67+
$cmd->stdout_is_eq("");
68+
$cmd->stderr_is_eq("fping: target name too long\n");
69+
}
70+
71+
{
72+
# a too long word starting with the second part of the line (256B buffer)
73+
# (no newline)
74+
my $tmpfile = File::Temp->new();
75+
print $tmpfile " "x255 ."a"x300 .".invalid";
76+
close($tmpfile);
77+
78+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
79+
$cmd->exit_is_num(1);
80+
$cmd->stdout_is_eq("");
81+
$cmd->stderr_is_eq("fping: target name too long\n");
82+
}
83+
84+
{
85+
# first part of line read into buffer may be blank
86+
my $tmpfile = File::Temp->new();
87+
print $tmpfile " "x400 ."a"x300 .".invalid\n";
88+
close($tmpfile);
89+
90+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
91+
$cmd->exit_is_num(1);
92+
$cmd->stdout_is_eq("");
93+
$cmd->stderr_is_eq("fping: target name too long\n");
94+
}
95+
96+
{
97+
# first part of line read into buffer may be blank
98+
# (no newline)
99+
my $tmpfile = File::Temp->new();
100+
print $tmpfile " "x400 ."a"x300 .".invalid";
101+
close($tmpfile);
102+
103+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
104+
$cmd->exit_is_num(1);
105+
$cmd->stdout_is_eq("");
106+
$cmd->stderr_is_eq("fping: target name too long\n");
107+
}
108+
109+
{
110+
# lines longer than the line buffer shall not be split - 132B buffer
111+
my $tmpfile = File::Temp->new();
112+
print $tmpfile " "x100 ."127.0.0.1 "." "x(131-9)."host.name.invalid\n";
113+
print $tmpfile " "x122 ."127.0.0.2 "." "x(131-9)."host.name.invalid\n";
114+
print $tmpfile " "x127 ."127.0.0.3 "." "x(131-9)."host.name.invalid\n";
115+
print $tmpfile " "x131 ."127.0.0.4 "." "x(131-9)."host.name.invalid\n";
116+
print $tmpfile " "x150 ."127.0.0.5 "." "x(131-9)."host.name.invalid\n";
117+
close($tmpfile);
118+
119+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
120+
$cmd->exit_is_num(0);
121+
$cmd->stdout_is_eq("127.0.0.1 is alive
122+
127.0.0.2 is alive
123+
127.0.0.3 is alive
124+
127.0.0.4 is alive
125+
127.0.0.5 is alive\n");
126+
$cmd->stderr_is_eq("");
127+
}
128+
129+
{
130+
# lines longer than the line buffer shall not be split - 132B buffer
131+
# (last line without newline)
132+
my $tmpfile = File::Temp->new();
133+
print $tmpfile " "x100 ."127.0.0.1 "." "x(131-9)."host.name.invalid\n";
134+
print $tmpfile " "x122 ."127.0.0.2 "." "x(131-9)."host.name.invalid\n";
135+
print $tmpfile " "x127 ."127.0.0.3 "." "x(131-9)."host.name.invalid\n";
136+
print $tmpfile " "x131 ."127.0.0.4 "." "x(131-9)."host.name.invalid\n";
137+
print $tmpfile " "x150 ."127.0.0.5 "." "x(131-9)."host.name.invalid";
138+
close($tmpfile);
139+
140+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
141+
$cmd->exit_is_num(0);
142+
$cmd->stdout_is_eq("127.0.0.1 is alive
143+
127.0.0.2 is alive
144+
127.0.0.3 is alive
145+
127.0.0.4 is alive
146+
127.0.0.5 is alive\n");
147+
$cmd->stderr_is_eq("");
148+
}
149+
150+
{
151+
# lines longer than the line buffer shall not be split - 256B buffer
152+
my $tmpfile = File::Temp->new();
153+
print $tmpfile " "x240 ."127.0.0.1 "." "x(255-9)."host.name.invalid\n";
154+
print $tmpfile " "x246 ."127.0.0.2 "." "x(255-9)."host.name.invalid\n";
155+
print $tmpfile " "x251 ."127.0.0.3 "." "x(255-9)."host.name.invalid\n";
156+
print $tmpfile " "x255 ."127.0.0.4 "." "x(255-9)."host.name.invalid\n";
157+
print $tmpfile " "x275 ."127.0.0.5 "." "x(255-9)."host.name.invalid\n";
158+
close($tmpfile);
159+
160+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
161+
$cmd->exit_is_num(0);
162+
$cmd->stdout_is_eq("127.0.0.1 is alive
163+
127.0.0.2 is alive
164+
127.0.0.3 is alive
165+
127.0.0.4 is alive
166+
127.0.0.5 is alive\n");
167+
$cmd->stderr_is_eq("");
168+
}
169+
170+
{
171+
# lines longer than the line buffer shall not be split - 256B buffer
172+
# (last line without newline)
173+
my $tmpfile = File::Temp->new();
174+
print $tmpfile " "x240 ."127.0.0.1 "." "x(255-9)."host.name.invalid\n";
175+
print $tmpfile " "x246 ."127.0.0.2 "." "x(255-9)."host.name.invalid\n";
176+
print $tmpfile " "x251 ."127.0.0.3 "." "x(255-9)."host.name.invalid\n";
177+
print $tmpfile " "x255 ."127.0.0.4 "." "x(255-9)."host.name.invalid\n";
178+
print $tmpfile " "x275 ."127.0.0.5 "." "x(255-9)."host.name.invalid";
179+
close($tmpfile);
180+
181+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
182+
$cmd->exit_is_num(0);
183+
$cmd->stdout_is_eq("127.0.0.1 is alive
184+
127.0.0.2 is alive
185+
127.0.0.3 is alive
186+
127.0.0.4 is alive
187+
127.0.0.5 is alive\n");
188+
$cmd->stderr_is_eq("");
189+
}
190+
191+
{
192+
# line without newline shorter than 131 bytes
193+
my $tmpfile = File::Temp->new();
194+
print $tmpfile " "x(131-10-9) ."127.0.0.1";
195+
close($tmpfile);
196+
197+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
198+
$cmd->exit_is_num(0);
199+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
200+
$cmd->stderr_is_eq("");
201+
}
202+
203+
{
204+
# line without newline with 131 bytes
205+
my $tmpfile = File::Temp->new();
206+
print $tmpfile " "x(131-9) ."127.0.0.1";
207+
close($tmpfile);
208+
209+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
210+
$cmd->exit_is_num(0);
211+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
212+
$cmd->stderr_is_eq("");
213+
}
214+
215+
{
216+
# line without newline with length between 131 and 255 bytes
217+
my $tmpfile = File::Temp->new();
218+
print $tmpfile " "x(255-10-9) ."127.0.0.1";
219+
close($tmpfile);
220+
221+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
222+
$cmd->exit_is_num(0);
223+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
224+
$cmd->stderr_is_eq("");
225+
}
226+
227+
{
228+
# line without newline with 255 bytes
229+
my $tmpfile = File::Temp->new();
230+
print $tmpfile " "x(255-9) ."127.0.0.1";
231+
close($tmpfile);
232+
233+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
234+
$cmd->exit_is_num(0);
235+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
236+
$cmd->stderr_is_eq("");
237+
}
238+
239+
{
240+
# line without newline with word split between two 256 byte buffers
241+
my $tmpfile = File::Temp->new();
242+
print $tmpfile " "x(255-5) ."127.0.0.1";
243+
close($tmpfile);
244+
245+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
246+
$cmd->exit_is_num(0);
247+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
248+
$cmd->stderr_is_eq("");
249+
}
250+
251+
{
252+
# line without newline with between 255 and 510 bytes
253+
my $tmpfile = File::Temp->new();
254+
print $tmpfile " "x(255*2-10-9) ."127.0.0.1";
255+
close($tmpfile);
256+
257+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
258+
$cmd->exit_is_num(0);
259+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
260+
$cmd->stderr_is_eq("");
261+
}
262+
263+
{
264+
# line without newline with 510 bytes
265+
my $tmpfile = File::Temp->new();
266+
print $tmpfile " "x(255*2-9) ."127.0.0.1";
267+
close($tmpfile);
268+
269+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
270+
$cmd->exit_is_num(0);
271+
$cmd->stdout_is_eq("127.0.0.1 is alive\n");
272+
$cmd->stderr_is_eq("");
273+
}
274+
275+
{
276+
# invalid target name with a comment sign inside
277+
my $tmpfile = File::Temp->new();
278+
for (my $i = 1; $i < 4; $i++) {
279+
print $tmpfile " "x(255-11+$i)."127.0.0.$i#host.name.invalid\n";
280+
}
281+
close($tmpfile);
282+
283+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
284+
$cmd->exit_is_num(2);
285+
$cmd->stdout_is_eq("");
286+
$cmd->stderr_like(qr{127\.0\.0\.1\#host\.name\.invalid: .*
287+
127\.0\.0\.2\#host\.name\.invalid: .*
288+
127\.0\.0\.3\#host\.name\.invalid: .*\n});
289+
}
290+
291+
{
292+
# blank lines are ignored
293+
my $tmpfile = File::Temp->new();
294+
print $tmpfile " "x100 ."\n";
295+
print $tmpfile " "x131 ."\n";
296+
print $tmpfile " "x150 ."\n";
297+
print $tmpfile " "x255 ."\n";
298+
print $tmpfile " "x275 ."\n";
299+
print $tmpfile " "x500 ."\n";
300+
print $tmpfile " "x510 ."\n";
301+
print $tmpfile " "x550 ."\n";
302+
print $tmpfile " "x575;
303+
close($tmpfile);
304+
305+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
306+
$cmd->exit_is_num(1);
307+
$cmd->stdout_is_eq("");
308+
$cmd->stderr_is_eq("");
309+
}
310+
311+
{
312+
# many comment lines, most needing more than one 256B buffer
313+
my $tmpfile = File::Temp->new();
314+
for (my $i = 1; $i < 4; $i++) {
315+
print $tmpfile " "x(255-11+$i)."# this is a comment\n";
316+
}
317+
for (my $i = 1; $i < 8; $i++) {
318+
print $tmpfile " "x(255-8+$i)."# x y z\n";
319+
}
320+
print $tmpfile "#"." "x300 ."localhost\n";
321+
print $tmpfile " "x300 ."#"." "x300 ."127.0.0.1\n";
322+
close($tmpfile);
323+
324+
my $cmd = Test::Command->new(cmd => "cat ".$tmpfile->filename." | fping");
325+
$cmd->exit_is_num(1);
326+
$cmd->stdout_is_eq("");
327+
$cmd->stderr_is_eq("");
328+
}

doc/fping.pod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ The number of addresses that can be generated using the C<-g>, C<--generate>
327327
option is limited to 131072 (the number of host addresses in one 111-bit IPv6
328328
prefix, two addresses more than the host addresses in one 15-bit IPv4 prefix).
329329

330+
The length of target names read from file or standard input is limited to
331+
255 bytes.
332+
330333
If fping was configured with C<--enable-safe-limits>, the following values are
331334
not allowed for non-root users:
332335

0 commit comments

Comments
 (0)