1 /* ping.c - check network connectivity
2  *
3  * Copyright 2014 Rob Landley <rob@landley.net>
4  *
5  * Not in SUSv4.
6 
7 USE_PING(NEWTOY(ping, "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]", TOYFLAG_ROOTONLY|TOYFLAG_USR|TOYFLAG_BIN))
8 
9 config PING
10   bool "ping"
11   default n
12   help
13     usage: ping [OPTIONS] HOST
14 
15     Check network connectivity by sending packets to a host and reporting
16     its response.
17 
18     Send ICMP ECHO_REQUEST packets to ipv4 or ipv6 addresses and prints each
19     echo it receives back, with round trip time.
20 
21     Options:
22     -4, -6      Force IPv4 or IPv6
23     -c CNT      Send CNT many packets
24     -I IFACE/IP Source interface or address
25     -q          Quiet, only displays output at start and when finished
26     -s SIZE     Packet SIZE in bytes (default 56)
27     -t TTL      Set Time (number of hops) To Live
28     -W SEC      Seconds to wait for response after all packets sent (default 10)
29     -w SEC      Exit after this many seconds
30 */
31 
32 #define FOR_ping
33 #include "toys.h"
34 
35 #include <ifaddrs.h>
36 
GLOBALS(long wait_exit;long wait_resp;char * iface;long size;long count;long ttl;int sock;)37 GLOBALS(
38   long wait_exit;
39   long wait_resp;
40   char *iface;
41   long size;
42   long count;
43   long ttl;
44 
45   int sock;
46 )
47 
48 void ping_main(void)
49 {
50   int family, protocol;
51   union {
52     struct in_addr in;
53     struct in6_addr in6;
54   } src_addr;
55   char *host = 0;
56 
57   // Determine IPv4 vs IPv6 type
58 
59   if(!(toys.optflags & (FLAG_4|FLAG_6))) {
60 // todo getaddrinfo instead?
61     if (inet_pton(AF_INET6, toys.optargs[0], (void*)&src_addr))
62       toys.optflags |= FLAG_6;
63   }
64 
65   if (toys.optflags & FLAG_6) {
66     family = AF_INET6;
67     protocol = IPPROTO_ICMPV6;
68   } else {
69     family = AF_INET;
70     protocol = IPPROTO_ICMP;
71   }
72 
73   if (!(toys.optflags & FLAG_s)) TT.size = 56; // 64-PHDR_LEN
74 
75   if (TT.iface) {
76     memset(&src_addr, 0, sizeof(src_addr));
77 
78     // IP address?
79     if (!inet_pton(family, TT.iface, &src_addr)) {
80       struct ifaddrs *ifsave, *ifa = 0;
81 
82       // Interface name?
83       if (!getifaddrs(&ifsave)) {
84         for (ifa = ifsave; ifa; ifa = ifa->ifa_next) {
85           if (!ifa->ifa_addr || ifa->ifa_addr->sa_family != family) continue;
86           if (!strcmp(ifa->ifa_name, TT.iface)) {
87             if (family == AF_INET)
88               memcpy(&src_addr,
89                 &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
90                 sizeof(struct in_addr));
91             else memcpy(&src_addr,
92                 &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr,
93                 sizeof(struct in6_addr));
94             break;
95           }
96         }
97         freeifaddrs(ifsave);
98       }
99       if (!ifa)
100         error_exit("no v%d addr for -I %s", 4+2*(family==AF_INET6), TT.iface);
101     }
102     inet_ntop(family, &src_addr, toybuf, sizeof(toybuf));
103     host = xstrdup(toybuf);
104   }
105 
106 printf("host=%s\n", host);
107 
108   // Open raw socket
109   TT.sock = xsocket(family, SOCK_RAW, protocol);
110 }
111