Sorry for slow reply...

On Mon, Jan 25, 2010 at 05:31:39AM -0500, Thomas Guyot-Sionnest wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 22/01/10 06:41 PM, Jan Wagner wrote:
> > Hi Matija,
> > 
> > I just fixed #534604 but not #51458, the changelog is just wrong. But I 
> > pinged 
> > upstream about you patch, if its a valid change for all conditions ... 
> > Actually there is just more evaluation needed by upstream.
> 
> I have looked a bit into this, I'm just afraid of changing it without
> the ability to test myself as it has the potential to break many other
> architecture I don't have access to.
> 
> If you can give me more details like which OS, software version and
> network condition (i.e. what happen when you get "+n errors"). Id your
> OS is Linux x86 32 or 64 bit you could even send me the binary and I may
> be able to run it locally to reproduce it.

It was Debian Etch when it was reported, now it is debian Lenny (same
symptoms, patch is just a few lines lower but applies cleanly).
Package with ping6 (in Lenny) used is iputils-ping 3:20071127-1

so you can grab the binaries from
http://packages.debian.org/search?keywords=iputils-ping

It is the same bug with either i386 or amd64 architecture.

To reproduce, here is example I get when I try to ping nonexistent
IPv6 address (your output might be different due to routers involved,
but hopefully would be in the same format):

% ping6 -c3 2a00:1450:8001::1234
PING 2a00:1450:8001::1234(2a00:1450:8001::1234) 56 data bytes
>From 2001:4860:0:1::1d icmp_seq=2 Destination unreachable: Address unreachable
>From 2001:4860:0:1::1b icmp_seq=3 Destination unreachable: Address unreachable

--- 2a00:1450:8001::1234 ping statistics ---
3 packets transmitted, 0 received, +2 errors, 100% packet loss, time 2003ms

when you try to use check_ping v1991 (nagios-plugins 1.4.12) you get

% ./check_ping -H 2a00:1450:8001::1234 -w 5000,100% -c 5000,100% -p 1
/bin/ping6 -n -U -w 10 -c 1 2a00:1450:8001::1234
CRITICAL - Could not interpret output from ping command

Now, if you apply the patch ping-sscanf.diff from
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=514588
you will get the correct answer:

% ./check_ping -H 2a00:1450:8001::1234 -w 5000,100% -c 5000,100% -p 1
PING CRITICAL - Packet loss = 
100%|rta=5000.000000ms;5000.000000;5000.000000;0.000000 pl=100%;100;100;0

(note that in our real world case we actually had a flaky network
and the IPv6 address was right, but the output format was the same,
only we did not have 100% lost but less etc -- but we couldn't get
that data from check_ping plugin as it couldn't interpret the output).

The problematic code lies in check_ping.c around line 455:

455 if(sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d errors, 
%d%% packet loss",&pl)==1 ||
456         sscanf(buf,"%*d packets transmitted, %*d packets received, +%*d 
duplicates, %d%% packet loss", &pl) == 1 ||
457         sscanf(buf,"%*d packets transmitted, %*d received, +%*d duplicates, 
%d%% packet loss", &pl) == 1 ||
458         sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% 
packet loss",&pl)==1 ||
459         sscanf(buf,"%*d packets transmitted, %*d packets received, %d%% 
loss, time",&pl)==1 || 
460         sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, 
time", &pl)==1 ||
461         sscanf(buf,"%*d packets transmitted, %*d received, %d%% packet 
loss, time", &pl)==1 ||
462         sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, 
%d%% packet loss", &pl) == 1 ||
463         sscanf(buf,"%*d packets transmitted %*d received, +%*d errors, %d%% 
packet loss", &pl) == 1

As you can see, our summary line from ping6 
"3 packets transmitted, 0 received, +2 errors, 100% packet loss, time 2003ms"

should have matched at line 462, at:
sscanf(buf,"%*d packets transmitted, %*d received, +%*d errors, %d%% packet 
loss", &pl) == 1
as that is the only line with string that would match, right ?

unfortunately, it will actually match at line 460, at
sscanf(buf,"%*d packets transmitted, %*d received, %d%% loss, time", &pl)==1

which is completely wrong, as that is not our string at all!

Careful reading of sscanf(3) reveals the problem -- the sscanf(3)
does not at all work like perl or similar languages. The return value
of sscanf(3) is instead number of arguments matched, and *not* the
claim that the *whole* string matched. That is, any and all text
after last "%d" is completely ignored (that is, no matter if they
match or not, the sscanf will return the same value - number of %
arguments matched so far: 1 in our case).

So line 460 might as well be written as:
sscanf(buf,"%*d packets transmitted, %*d received, %d", &pl)==1

which shows more clearly why it breaks.

Now the patch might look like it changes a lot but that is only
because diff is line oriented -- we're actually just adding "%n" at
the end of each line (and &match variable to store it) to be sure
*the whole* line matched, not just a part up to last "%d".

I hope this gives you enough info to check and validate the patch.

Thanks,
Matija Nalis



-- 
To UNSUBSCRIBE, email to [email protected]
with a subject of "unsubscribe". Trouble? Contact [email protected]

Reply via email to