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

schweikert / fping / 23399440985

22 Mar 2026 08:45AM UTC coverage: 87.975% (-0.06%) from 88.037%
23399440985

Pull #463

github

web-flow
Merge 4bcab436b into b8626092d
Pull Request #463: New option --oiface for outgoing interface

49 of 59 new or added lines in 3 files covered. (83.05%)

14 existing lines in 2 files now uncovered.

1668 of 1896 relevant lines covered (87.97%)

346.15 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
int open_ping_socket_ipv4(int *socktype)
881✔
57
{
58
    struct protoent* proto;
59
    int s;
60

61
    /* confirm that ICMP is available on this machine */
62
    if ((proto = getprotobyname("icmp")) == NULL)
881✔
UNCOV
63
        crash_and_burn("icmp: unknown protocol");
×
64

65
    /* create raw socket for ICMP calls (ping) */
66
    *socktype = SOCK_RAW;
881✔
67
    s = socket(AF_INET, *socktype, proto->p_proto);
881✔
68
    if (s < 0) {
881✔
69
        /* try non-privileged icmp (works on Mac OSX without privileges, for example) */
70
        *socktype = SOCK_DGRAM;
12✔
71
        s = socket(AF_INET, *socktype, proto->p_proto);
12✔
72
        if (s < 0) {
12✔
UNCOV
73
            return -1;
×
74
        }
75
    }
76

77
    /* Make sure that we use non-blocking IO */
78
    {
79
        int flags;
80

81
        if ((flags = fcntl(s, F_GETFL, 0)) < 0)
881✔
UNCOV
82
            perror("fcntl");
×
83

84
        if (fcntl(s, F_SETFL, flags | O_NONBLOCK) < 0)
881✔
UNCOV
85
            perror("fcntl");
×
86
    }
87

88
    return s;
881✔
89
}
239✔
90

91
void socket_set_outgoing_iface_ipv4(int s, const char *iface_name)
4✔
92
{
93
    unsigned int idx = if_nametoindex(iface_name);
4✔
94
    if (idx == 0) {
4✔
NEW
95
        fprintf(stderr, "fping: unknown interface '%s'\n", iface_name);
×
NEW
96
        exit(1);
×
97
    }
98
    outgoing_iface_idx_ipv4 = (int)idx;
4✔
99

100
    int on = 1;
4✔
101
    if (setsockopt(s, IPPROTO_IP, IP_PKTINFO, &on, sizeof(on)) < 0) {
4✔
NEW
102
        perror("setsockopt IP_PKTINFO");
×
NEW
103
        exit(1);
×
104
    }
105
}
4✔
106

107
void init_ping_buffer_ipv4(size_t ping_data_size)
392✔
108
{
109
    /* allocate ping buffer */
110
    ping_pkt_size_ipv4 = ping_data_size + ICMP_MINLEN;
392✔
111
    ping_buffer_ipv4 = (char*)calloc(1, ping_pkt_size_ipv4);
392✔
112
    if (!ping_buffer_ipv4)
392✔
UNCOV
113
        crash_and_burn("can't malloc ping packet");
×
114
}
392✔
115

116
void socket_set_src_addr_ipv4(int s, struct in_addr* src_addr, int *ident)
18✔
117
{
118
    struct sockaddr_in sa;
119
    socklen_t len = sizeof(sa);
18✔
120

121
    memset(&sa, 0, len);
18✔
122
    sa.sin_family = AF_INET;
18✔
123
    sa.sin_addr = *src_addr;
18✔
124
    if (bind(s, (struct sockaddr*)&sa, len) < 0)
18✔
125
        errno_crash_and_burn("cannot bind source address");
3✔
126

127
    if (ident) {
16✔
128
        memset(&sa, 0, len);
12✔
129
        if (getsockname(s, (struct sockaddr *)&sa, &len) < 0)
12✔
UNCOV
130
            errno_crash_and_burn("can't get ICMP socket identity");
×
131

132
        if (sa.sin_port)
12✔
133
            *ident = sa.sin_port;
12✔
134
    }
135
}
16✔
136

137
unsigned short calcsum(unsigned short* buffer, int length)
918✔
138
{
139
    unsigned long sum;
140

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

145
    /* we may have an extra byte */
146
    if (length == 1)
918✔
UNCOV
147
        sum += (char)*buffer;
×
148

149
    sum = (sum >> 16) + (sum & 0xFFFF); /* add high 16 to low 16 */
918✔
150
    sum += (sum >> 16); /* add carry */
918✔
151
    return ~sum;
918✔
152
}
153

154
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✔
155
{
156
    struct icmp* icp;
157
    struct timespec tsorig;
158
    long tsorig_ms;
159
    int n;
160

161
    icp = (struct icmp*)ping_buffer_ipv4;
918✔
162

163
    icp->icmp_type = icmp_proto;
918✔
164
    if(icmp_proto == ICMP_TSTAMP) {
918✔
165
        clock_gettime(CLOCK_REALTIME, &tsorig);
18✔
166
        tsorig_ms = (tsorig.tv_sec % (24*60*60)) * 1000 + tsorig.tv_nsec / 1000000;
18✔
167
        icp->icmp_otime = htonl(tsorig_ms);
18✔
168
        icp->icmp_rtime = 0;
18✔
169
        icp->icmp_ttime = 0;
18✔
170
    }
171
    icp->icmp_code = 0;
918✔
172
    icp->icmp_cksum = 0;
918✔
173
    icp->icmp_seq = htons(icmp_seq_nr);
918✔
174
    icp->icmp_id = icmp_id_nr;
918✔
175

176
    if (opt_random_data_on) {
918✔
177
        for (n = ((char*)&icp->icmp_data - (char*)icp); n < ping_pkt_size_ipv4; ++n) {
513✔
178
            ping_buffer_ipv4[n] = random() & 0xFF;
504✔
179
        }
168✔
180
    }
3✔
181

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

184
    if (outgoing_iface_idx_ipv4 > 0) {
918✔
185
        struct iovec iov = {
2✔
186
            .iov_base = icp,
187
            .iov_len  = ping_pkt_size_ipv4
188
        };
189

190
        char cmsg_buf[CMSG_SPACE(sizeof(struct in_pktinfo))];
191
        memset(cmsg_buf, 0, sizeof(cmsg_buf));
2✔
192

193
        struct msghdr msg = {
2✔
194
            .msg_name       = saddr,
195
            .msg_namelen    = saddr_len,
196
            .msg_iov        = &iov,
197
            .msg_iovlen     = 1,
198
            .msg_control    = cmsg_buf,
199
            .msg_controllen = sizeof(cmsg_buf),
200
            .msg_flags      = 0
201
        };
202

203
        struct cmsghdr *cmsg = CMSG_FIRSTHDR(&msg);
2✔
204
        cmsg->cmsg_level = IPPROTO_IP;
2✔
205
        cmsg->cmsg_type  = IP_PKTINFO;
2✔
206
        cmsg->cmsg_len   = CMSG_LEN(sizeof(struct in_pktinfo));
2✔
207

208
        struct in_pktinfo *pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsg);
2✔
209
        memset(pktinfo, 0, sizeof(*pktinfo));
2✔
210
        pktinfo->ipi_ifindex = outgoing_iface_idx_ipv4;
2✔
211

212
        n = sendmsg(s, &msg, 0);
2✔
213
    } else {
214
        n = sendto(s, icp, ping_pkt_size_ipv4, 0, saddr, saddr_len);
916✔
215
    }
216

217
    return n;
918✔
218
}
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