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

schweikert / fping / 26721634668

31 May 2026 07:01PM UTC coverage: 87.992% (-0.008%) from 88.0%
26721634668

Pull #470

github

web-flow
Merge cb15cc514 into 780ec4674
Pull Request #470: Fix getprotobyname missing on Android preventing use

14 of 16 new or added lines in 2 files covered. (87.5%)

2 existing lines in 1 file now uncovered.

1678 of 1907 relevant lines covered (87.99%)

348.0 hits per line

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

87.5
/src/socket4.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
#include "flags.h"
36

37
#include <fcntl.h>
38
#include <netdb.h>
39
#include <netinet/in.h>
40
#include <netinet/in_systm.h>
41
#include <netinet/ip.h>
42
#include <netinet/ip_icmp.h>
43
#include <net/if.h>
44
#include <stdio.h>
45
#include <stdlib.h>
46
#include <string.h>
47
#include <sys/socket.h>
48
#include <time.h>
49

50
char* ping_buffer_ipv4 = 0;
51
size_t ping_pkt_size_ipv4;
52

53
/* Interface index for outgoing packets (0 = not set, use routing table) */
54
static int outgoing_iface_idx_ipv4 = 0;
55

56
/* Source address for outgoing packets (used to populate ipi_spec_dst) */
57
static struct in_addr outgoing_src_addr_ipv4;
58
static int outgoing_src_addr_set_ipv4 = 0;
59

60
int open_ping_socket_ipv4(int *socktype)
881✔
61
{
62
    int s = -1;
881✔
63
    int p_proto = IPPROTO_ICMP;
881✔
64

65
#ifdef USE_GETPROTOBYNAME
66
    {
67
        /* confirm that ICMP is available on this machine */
68
        struct protoent* proto = getprotobyname("icmp");
881✔
69
        if (proto == NULL) {
881✔
NEW
70
            crash_and_burn("icmp: unknown protocol");
×
71
        }
72
        p_proto = proto->p_proto;
881✔
73
    }
74
#endif
75

76
    /* create raw socket for ICMP calls (ping) */
77
    *socktype = SOCK_RAW;
881✔
78
    s = socket(AF_INET, *socktype, p_proto);
881✔
79
    if (s < 0) {
881✔
80
        /* try non-privileged icmp (works on Mac OSX without privileges, for example) */
81
        *socktype = SOCK_DGRAM;
12✔
82
        s = socket(AF_INET, *socktype, p_proto);
12✔
83
        if (s < 0) {
12✔
84
            return -1;
×
85
        }
86
    }
87

88
    /* Make sure that we use non-blocking IO */
89
    {
90
        int flags;
91

92
        if ((flags = fcntl(s, F_GETFL, 0)) < 0)
881✔
93
            perror("fcntl");
×
94

95
        if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
881✔
96
            perror("fcntl");
×
97
    }
98

99
    return s;
881✔
100
}
239✔
101

102
void socket_set_outgoing_iface_ipv4(int s, const char *iface_name)
4✔
103
{
104
    unsigned int idx = if_nametoindex(iface_name);
4✔
105
    if (idx == 0) {
4✔
106
        fprintf(stderr, "fping: unknown interface '%s'\n", iface_name);
×
107
        exit(1);
×
108
    }
109
    outgoing_iface_idx_ipv4 = (int)idx;
4✔
110

111
    int on = 1;
4✔
112
    if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) {
4✔
113
        perror("setsockopt IP_PKTINFO");
×
114
        exit(1);
×
115
    }
116
}
4✔
117

118
void init_ping_buffer_ipv4(size_t ping_data_size)
392✔
119
{
120
    /* allocate ping buffer */
121
    ping_pkt_size_ipv4 = ping_data_size + ICMP_MINLEN;
392✔
122
    ping_buffer_ipv4 = (char*)calloc(1, ping_pkt_size_ipv4);
392✔
123
    if (!ping_buffer_ipv4)
392✔
124
        crash_and_burn("can't malloc ping packet");
×
125
}
392✔
126

127
void socket_set_src_addr_ipv4(int s, struct in_addr* src_addr, int *ident)
18✔
128
{
129
    struct sockaddr_in sa;
130
    socklen_t len = sizeof(sa);
18✔
131

132
    /* Remember source address so we can set ipi_spec_dst in sendmsg() */
133
    outgoing_src_addr_ipv4 = *src_addr;
18✔
134
    outgoing_src_addr_set_ipv4 = 1;
18✔
135

136
    memset(&sa, 0, len);
18✔
137
    sa.sin_family = AF_INET;
18✔
138
    sa.sin_addr = *src_addr;
18✔
139
    if (bind(s, (struct sockaddr*)&sa, len) < 0)
18✔
140
        errno_crash_and_burn("cannot bind source address");
3✔
141

142
    if (ident) {
16✔
143
        memset(&sa, 0, len);
12✔
144
        if (getsockname(s, (struct sockaddr *)&sa, &len) < 0)
12✔
145
            errno_crash_and_burn("can't get ICMP socket identity");
×
146

147
        if (sa.sin_port)
12✔
148
            *ident = sa.sin_port;
12✔
149
    }
150
}
16✔
151

152
unsigned short calcsum(unsigned short* buffer, int length)
918✔
153
{
154
    unsigned long sum;
155

156
    /* initialize sum to zero and loop until length (in words) is 0 */
157
    for (sum = 0; length > 1; length -= 2) /* sizeof() returns number of bytes, we're interested in number of words */
31,314✔
158
        sum += *buffer++; /* add 1 word of buffer to sum and proceed to the next */
30,396✔
159

160
    /* we may have an extra byte */
161
    if (length == 1)
918✔
162
        sum += (char)*buffer;
×
163

164
    sum = (sum >> 16) + (sum & 0xFFFF); /* add high 16 to low 16 */
918✔
165
    sum += (sum >> 16); /* add carry */
918✔
166
    return ~sum;
918✔
167
}
168

169
int socket_sendto_ping_ipv4(int s, struct sockaddr* saddr, socklen_t saddr_len, uint16_t icmp_seq_nr, uint16_t icmp_id_nr, uint8_t icmp_proto)
918✔
170
{
171
    struct icmp* icp;
172
    struct timespec tsorig;
173
    long tsorig_ms;
174
    int n;
175

176
    icp = (struct icmp*)ping_buffer_ipv4;
918✔
177

178
    icp->icmp_type = icmp_proto;
918✔
179
    if(icmp_proto == ICMP_TSTAMP) {
918✔
180
        clock_gettime(CLOCK_REALTIME, &tsorig);
18✔
181
        tsorig_ms = (tsorig.tv_sec % (24*60*60)) * 1000 + tsorig.tv_nsec / 1000000;
18✔
182
        icp->icmp_otime = htonl(tsorig_ms);
18✔
183
        icp->icmp_rtime = 0;
18✔
184
        icp->icmp_ttime = 0;
18✔
185
    }
186
    icp->icmp_code = 0;
918✔
187
    icp->icmp_cksum = 0;
918✔
188
    icp->icmp_seq = htons(icmp_seq_nr);
918✔
189
    icp->icmp_id = icmp_id_nr;
918✔
190

191
    if (opt_random_data_on) {
918✔
192
        for (n = ((char*)&icp->icmp_data - (char*)icp); n < ping_pkt_size_ipv4; ++n) {
513✔
193
            ping_buffer_ipv4[n] = random() & 0xFF;
504✔
194
        }
168✔
195
    }
3✔
196

197
    icp->icmp_cksum = calcsum((unsigned short*)icp, ping_pkt_size_ipv4);
918✔
198

199
    if (outgoing_iface_idx_ipv4 > 0) {
918✔
200
        struct iovec iov = {
2✔
201
            .iov_base = icp,
202
            .iov_len  = ping_pkt_size_ipv4
203
        };
204

205
        char cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
206
        memset(cmsg_buf, 0, sizeof(cmsg_buf));
2✔
207

208
        struct msghdr msg = {
2✔
209
            .msg_name       = saddr,
210
            .msg_namelen    = saddr_len,
211
            .msg_iov        = &iov,
212
            .msg_iovlen     = 1,
213
            .msg_control    = cmsg_buf,
214
            .msg_controllen = sizeof(cmsg_buf),
215
            .msg_flags      = 0
216
        };
217

218
        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
2✔
219
        cmsg->cmsg_level = IPPROTO_IP;
2✔
220
        cmsg->cmsg_type  = IP_PKTINFO;
2✔
221
        cmsg->cmsg_len   = CMSG_LEN(sizeof(struct in_pktinfo));
2✔
222

223
        struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
2✔
224
        memset(pktinfo, 0, sizeof(*pktinfo));
2✔
225
        pktinfo->ipi_ifindex = outgoing_iface_idx_ipv4;
2✔
226
        if (outgoing_src_addr_set_ipv4) {
2✔
227
            pktinfo->ipi_spec_dst = outgoing_src_addr_ipv4;
×
228
        }
229

230
        n = sendmsg(s, &msg, 0);
2✔
231
    } else {
232
        n = sendto(s, icp, ping_pkt_size_ipv4, 0, saddr, saddr_len);
916✔
233
    }
234

235
    return n;
918✔
236
}
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