• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

schweikert / fping / 16249769098

13 Jul 2025 01:42PM UTC coverage: 86.308% (-1.3%) from 87.577%
16249769098

push

github

auerswal
fix ICMPv6 error message handling and reporting

Handling of received ICMPv6 messages different from Echo Reply
was based on IPv4 code.  It would thus use a too small minimum
size, and interpret the wrong data as ICMPv6 fields.  Thus
received ICMPv6 error messages were either not reported at all,
or were reported incorrectly.

This commit introduces the following changes to fix this and thus
address GitHub issue #390:

- Filter out irrelevant ICMPv6 messages: fping needs to receive
  ICMPv6 Echo Reply and ICMPv6 error messages, nothing else
  (only relevant for raw sockets).
- Fix offset calculation to look at the included packet that
  caused this ICMPv6 error message.
- Ignore invoking packets that do not have ICMPv6 as the first
  IPv6 Next Header in the packet (there could be, e.g., IPv6
  Extension Headers).
- Fix ICMPv6 message type determination, and print respective
  warning messages.

7 of 41 new or added lines in 2 files covered. (17.07%)

6 existing lines in 1 file now uncovered.

1557 of 1804 relevant lines covered (86.31%)

331.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.5
/src/socket6.c
1
/*
2
 * fping: fast-ping, file-ping, favorite-ping, funky-ping
3
 *
4
 *   Ping a list of target hosts in a round robin fashion.
5
 *   A better ping overall.
6
 *
7
 * fping website:  http://www.fping.org
8
 *
9
 * Current maintainer of fping: David Schweikert
10
 * Please send suggestions and patches to: david@schweikert.ch
11
 *
12
 *
13
 * Original author:  Roland Schemers  <schemers@stanford.edu>
14
 * IPv6 Support:     Jeroen Massar    <jeroen@unfix.org / jeroen@ipng.nl>
15
 * Improved main loop: David Schweikert <david@schweikert.ch>
16
 * Debian Merge, TOS settings: Tobi Oetiker <tobi@oetiker.ch>
17
 * Bugfixes, byte order & senseful seq.-numbers: Stephan Fuhrmann (stephan.fuhrmann AT 1und1.de)
18
 *
19
 *
20
 * Redistribution and use in source and binary forms are permitted
21
 * provided that the above copyright notice and this paragraph are
22
 * duplicated in all such forms and that any documentation,
23
 * advertising materials, and other materials related to such
24
 * distribution and use acknowledge that the software was developed
25
 * by Stanford University.  The name of the University may not be used
26
 * to endorse or promote products derived from this software without
27
 * specific prior written permission.
28
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
29
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
30
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
31
 */
32

33
#include "config.h"
34
#include "fping.h"
35

36
#include <fcntl.h>
37
#include <netdb.h>
38
#include <netinet/in.h>
39
#include <stdio.h>
40
#include <stdlib.h>
41
#include <string.h>
42
#include <sys/socket.h>
43

44
#include <netinet/icmp6.h>
45

46
char* ping_buffer_ipv6 = 0;
47
size_t ping_pkt_size_ipv6;
48

49
int open_ping_socket_ipv6(int *socktype)
690✔
50
{
51
    struct protoent* proto;
52
    int s;
53

54
    /* confirm that ICMP6 is available on this machine */
55
    if ((proto = getprotobyname("ipv6-icmp")) == NULL)
690✔
56
        crash_and_burn("ipv6-icmp: unknown protocol");
×
57

58
    /* create raw socket for ICMP6 calls (ping) */
59
    *socktype = SOCK_RAW;
690✔
60
    s = socket(AF_INET6, *socktype, proto->p_proto);
690✔
61
    if (s < 0) {
690✔
62
        /* try non-privileged icmp6 (works on Mac OSX without privileges, for example) */
63
        *socktype = SOCK_DGRAM;
12✔
64
        s = socket(AF_INET6, *socktype, proto->p_proto);
12✔
65
        if (s < 0) {
12✔
66
            return -1;
×
67
        }
68
    } else {
69
        /* receive only ICMP6 messages relevant for fping on raw socket */
70
        struct icmp6_filter recv_filter;
71

72
        ICMP6_FILTER_SETBLOCKALL(&recv_filter);
678✔
73
        ICMP6_FILTER_SETPASS(ICMP6_ECHO_REPLY, &recv_filter);
678✔
74
        ICMP6_FILTER_SETPASS(ICMP6_DST_UNREACH, &recv_filter);
678✔
75
        ICMP6_FILTER_SETPASS(ICMP6_PACKET_TOO_BIG, &recv_filter);
678✔
76
        ICMP6_FILTER_SETPASS(ICMP6_TIME_EXCEEDED, &recv_filter);
678✔
77
        ICMP6_FILTER_SETPASS(ICMP6_PARAM_PROB, &recv_filter);
678✔
78

79
        if (setsockopt(s, IPPROTO_ICMPV6, ICMP6_FILTER, &recv_filter, sizeof(recv_filter))) {
678✔
NEW
80
            errno_crash_and_burn("cannot set icmp6 message type filter");
×
81
        }
82
    }
83

84
    /* Make sure that we use non-blocking IO */
85
    {
86
        int flags;
87

88
        if ((flags = fcntl(s, F_GETFL, 0)) < 0)
690✔
89
            perror("fcntl");
×
90

91
        if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
690✔
92
            perror("fcntl");
×
93
    }
94

95
    return s;
690✔
96
}
186✔
97

98
void init_ping_buffer_ipv6(size_t ping_data_size)
373✔
99
{
100
    /* allocate ping buffer */
101
    ping_pkt_size_ipv6 = ping_data_size + sizeof(struct icmp6_hdr);
373✔
102
    ping_buffer_ipv6 = (char*)calloc(1, ping_pkt_size_ipv6);
373✔
103
    if (!ping_buffer_ipv6)
373✔
104
        crash_and_burn("can't malloc ping packet");
×
105
}
373✔
106

107
void socket_set_src_addr_ipv6(int s, struct in6_addr* src_addr, int *ident)
16✔
108
{
109
    struct sockaddr_in6 sa;
110
    socklen_t len = sizeof(sa);
16✔
111

112
    memset(&sa, 0, sizeof(sa));
16✔
113
    sa.sin6_family = AF_INET6;
16✔
114
    sa.sin6_addr = *src_addr;
16✔
115
    if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0)
16✔
116
        errno_crash_and_burn("cannot bind source address");
2✔
117

118
    if (ident) {
14✔
119
        memset(&sa, 0, len);
12✔
120
        if (getsockname(s, (struct sockaddr *)&sa, &len) < 0)
12✔
121
            errno_crash_and_burn("can't get ICMP6 socket identity");
×
122

123
        if (sa.sin6_port)
12✔
124
            *ident = sa.sin6_port;
12✔
125
    }
126
}
14✔
127

128
int socket_sendto_ping_ipv6(int s, struct sockaddr* saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr)
123✔
129
{
130
    struct icmp6_hdr* icp;
131
    int n;
132

133
    icp = (struct icmp6_hdr*)ping_buffer_ipv6;
123✔
134
    icp->icmp6_type = ICMP6_ECHO_REQUEST;
123✔
135
    icp->icmp6_code = 0;
123✔
136
    icp->icmp6_seq = htons(icmp_seq_nr);
123✔
137
    icp->icmp6_id = icmp_id_nr;
123✔
138

139
    if (random_data_flag) {
123✔
140
        for (n = sizeof(struct icmp6_hdr); n < ping_pkt_size_ipv6; ++n) {
342✔
141
            ping_buffer_ipv6[n] = random() & 0xFF;
336✔
142
        }
143
    }
144

145
    icp->icmp6_cksum = 0; /* The IPv6 stack calculates the checksum for us... */
123✔
146

147
    n = sendto(s, icp, ping_pkt_size_ipv6, 0, saddr, saddr_len);
123✔
148

149
    return n;
123✔
150
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc