aboutsummaryrefslogtreecommitdiff
path: root/toys/pending/ping.c
blob: 545ad79cdc101545b29f1c71bb371beb47d78754 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
/* ping.c - check network connectivity
 *
 * Copyright 2014 Rob Landley <rob@landley.net>
 *
 * Not in SUSv4.
 
USE_PING(NEWTOY(ping, "<1>1t#<0>255c#<0s#<0>65535I:W#<0w#<0q46[-46]", TOYFLAG_ROOTONLY|TOYFLAG_USR|TOYFLAG_BIN))
 
config PING
  bool "ping"
  default n
  help
    usage: ping [OPTIONS] HOST

    Check network connectivity by sending packets to a host and reporting
    its response.

    Send ICMP ECHO_REQUEST packets to ipv4 or ipv6 addresses and prints each
    echo it receives back, with round trip time.

    Options:
    -4, -6      Force IPv4 or IPv6
    -c CNT      Send CNT many packets
    -I IFACE/IP Source interface or address
    -q          Quiet, only displays output at start and when finished
    -s SIZE     Packet SIZE in bytes (default 56)
    -t TTL      Set Time (number of hops) To Live
    -W SEC      Seconds to wait for response after all packets sent (default 10)
    -w SEC      Exit after this many seconds
*/

#define FOR_ping 
#include "toys.h"

#include <ifaddrs.h>

GLOBALS(
  long wait_exit;
  long wait_resp;
  char *iface;
  long size;
  long count;
  long ttl;

  int sock;
)

void *sock2addr(struct sockaddr *sa)
{
  if (sa->sa_family == AF_INET)
    return &((struct sockaddr_in *)sa)->sin_addr;
  return &((struct sockaddr_in6 *)sa)->sin6_addr;
}

void ping_main(void)
{
  struct addrinfo *ai, *ai2;
  struct ifaddrs *ifa, *ifa2 = 0;
  union {
    struct sockaddr_in in;
    struct sockaddr_in6 in6;
  } src_addr;
  struct sockaddr *sa = (void *)&src_addr;
  int family = 0;

  // no 4/6 specified: -I has only one, arg must match
  // no 4/6 specified: arg is one, -I must match
  // 4/6 specified, both must match

  if (!(toys.optflags&FLAG_s)) TT.size = 56; // 64-PHDR_LEN
  if (toys.optflags&FLAG_6) family = AF_INET6;
  else if (toys.optflags&FLAG_4) family = AF_INET;
  else family = 0;

  // If -I src_addr look it up. Allow numeric address of correct type.
  memset(&src_addr, 0, sizeof(src_addr));
  if (TT.iface) {
    if (!(toys.optflags&FLAG_6) && inet_pton(AF_INET, TT.iface,
      (void *)&src_addr.in.sin_addr))
        family = sa->sa_family = AF_INET;
    else if (!(toys.optflags&FLAG_4) && inet_pton(AF_INET6, TT.iface,
      (void *)&src_addr.in6.sin6_addr))
        family = sa->sa_family = AF_INET6;
    else if (getifaddrs(&ifa2)) perror_exit("getifaddrs");
  }

  // Look up HOST address, filtering for correct type.
  // If -I but no -46 then find compatible type between -I and HOST
  ai2 = xgetaddrinfo(toys.optargs[0], 0, family, 0, 0, 0);
  for (ai = ai2; ai; ai = ai->ai_next) {
    if (family && family!=ai->ai_family) continue;
    if (ai->ai_family!=AF_INET && ai->ai_family!=AF_INET6) continue;
    if (!TT.iface || !ifa2) break;
    for (ifa = ifa2; ifa; ifa = ifa->ifa_next) {
      if (!ifa->ifa_addr || ifa->ifa_addr->sa_family!=ai->ai_family
          || strcmp(ifa->ifa_name, TT.iface)) continue;
      sa = (void *)ifa->ifa_addr;

      break;
    }
    if (ifa) break;
  }

  if (!ai)
    error_exit("no v%d addr for -I %s", 4+2*(family==AF_INET6), TT.iface);

  inet_ntop(family, sock2addr(sa), toybuf, sizeof(toybuf));
  printf("host=%s\n", toybuf);
  *toybuf = 0;
  inet_ntop(ai->ai_family, sock2addr(ai->ai_addr), toybuf, sizeof(toybuf));
  printf("targ=%s\n", toybuf);

  // Open raw socket
  TT.sock = xsocket(ai->ai_family, SOCK_DGRAM, (ifa->ifa_addr->sa_family == AF_INET) ?
    IPPROTO_ICMP : IPPROTO_ICMPV6);
  if (TT.iface && bind(TT.sock, ifa->ifa_addr, sizeof(src_addr)))
    perror_exit("bind");

  if (CFG_TOYBOX_FREE) {
    freeaddrinfo(ai2);
    if (ifa2) freeifaddrs(ifa2);
  }
}