1/* ping.c - check network connectivity
2 *
3 * Copyright 2014 Rob Landley <rob@landley.net>
4 *
5 * Not in SUSv4.
6
7USE_PING(NEWTOY(ping, "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]", TOYFLAG_ROOTONLY|TOYFLAG_USR|TOYFLAG_BIN))
8
9config 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
37GLOBALS(
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
48void 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
106printf("host=%s\n", host);
107
108  // Open raw socket
109  TT.sock = xsocket(family, SOCK_RAW, protocol);
110}
111