1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (C) 2019 Jan Sucan <jansucan@FreeBSD.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 #include <sys/types.h> 31 #include <sys/socket.h> 32 33 #include <arpa/inet.h> 34 #include <netdb.h> 35 #include <netinet/in.h> 36 37 #include <err.h> 38 #include <stdbool.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <unistd.h> 43 44 #include "main.h" 45 #ifdef INET 46 #include "ping.h" 47 #endif 48 #ifdef INET6 49 #include "ping6.h" 50 #endif 51 52 #if defined(INET) && defined(INET6) 53 #define OPTSTR PING6OPTS PING4OPTS 54 #elif defined(INET) 55 #define OPTSTR PING4OPTS 56 #elif defined(INET6) 57 #define OPTSTR PING6OPTS 58 #else 59 #error At least one of INET and INET6 is required 60 #endif 61 62 int 63 main(int argc, char *argv[]) 64 { 65 #if defined(INET) && defined(INET6) 66 struct in_addr a; 67 struct in6_addr a6; 68 #endif 69 #if defined(INET) || defined(INET6) 70 struct addrinfo hints; 71 #endif 72 int ch; 73 #ifdef INET 74 bool ipv4 = false; 75 #endif 76 #ifdef INET6 77 bool ipv6 = false; 78 79 if (strcmp(getprogname(), "ping6") == 0) 80 ipv6 = true; 81 #endif 82 83 while ((ch = getopt(argc, argv, ":" OPTSTR)) != -1) { 84 switch(ch) { 85 #ifdef INET 86 case '4': 87 ipv4 = true; 88 break; 89 #endif 90 #ifdef INET6 91 case '6': 92 ipv6 = true; 93 break; 94 #endif 95 #if defined(INET) && defined(INET6) 96 case 'S': 97 /* 98 * If -S is given with a numeric parameter, 99 * force use of the corresponding version. 100 */ 101 if (inet_pton(AF_INET, optarg, &a) == 1) 102 ipv4 = true; 103 else if (inet_pton(AF_INET6, optarg, &a6) == 1) 104 ipv6 = true; 105 break; 106 #endif 107 default: 108 break; 109 } 110 } 111 112 if (optind >= argc) 113 usage(); 114 115 optreset = 1; 116 optind = 1; 117 #if defined(INET) && defined(INET6) 118 if (ipv4 && ipv6) 119 errx(1, "-4 and -6 cannot be used simultaneously"); 120 #endif 121 122 #if defined(INET) && defined(INET6) 123 if (inet_pton(AF_INET, argv[argc - 1], &a) == 1) { 124 if (ipv6) 125 errx(1, "IPv6 requested but IPv4 target address " 126 "provided"); 127 hints.ai_family = AF_INET; 128 } 129 else if (inet_pton(AF_INET6, argv[argc - 1], &a6) == 1) { 130 if (ipv4) 131 errx(1, "IPv4 requested but IPv6 target address " 132 "provided"); 133 hints.ai_family = AF_INET6; 134 } else if (ipv6) 135 hints.ai_family = AF_INET6; 136 else if (ipv4) 137 hints.ai_family = AF_INET; 138 else { 139 if (!feature_present("inet6")) 140 hints.ai_family = AF_INET; 141 else if (!feature_present("inet")) 142 hints.ai_family = AF_INET6; 143 else { 144 struct addrinfo *res; 145 146 memset(&hints, 0, sizeof(hints)); 147 hints.ai_socktype = SOCK_RAW; 148 hints.ai_family = AF_UNSPEC; 149 getaddrinfo(argv[argc - 1], NULL, &hints, &res); 150 if (res != NULL) { 151 hints.ai_family = res[0].ai_family; 152 freeaddrinfo(res); 153 } 154 } 155 } 156 #elif defined(INET) 157 hints.ai_family = AF_INET; 158 #elif defined(INET6) 159 hints.ai_family = AF_INET6; 160 #endif 161 162 #ifdef INET 163 if (hints.ai_family == AF_INET) 164 return ping(argc, argv); 165 #endif /* INET */ 166 #ifdef INET6 167 if (hints.ai_family == AF_INET6) 168 return ping6(argc, argv); 169 #endif /* INET6 */ 170 errx(1, "Unknown host"); 171 } 172 173 void 174 usage(void) 175 { 176 (void)fprintf(stderr, 177 "usage:\n" 178 #ifdef INET 179 "\tping [-4AaDdfHnoQqRrv] [-C pcp] [-c count] " 180 "[-G sweepmaxsize]\n" 181 "\t [-g sweepminsize] [-h sweepincrsize] [-i wait] " 182 "[-l preload]\n" 183 "\t [-M mask | time] [-m ttl] " 184 #ifdef IPSEC 185 "[-P policy] " 186 #endif 187 "[-p pattern] [-S src_addr] \n" 188 "\t [-s packetsize] [-t timeout] [-W waittime] [-z tos] " 189 "IPv4-host\n" 190 "\tping [-4AaDdfHLnoQqRrv] [-C pcp] [-c count] [-I iface] " 191 "[-i wait]\n" 192 "\t [-l preload] [-M mask | time] [-m ttl] " 193 #ifdef IPSEC 194 "[-P policy] " 195 #endif 196 "[-p pattern]\n" 197 "\t [-S src_addr] [-s packetsize] [-T ttl] [-t timeout] [-W waittime]\n" 198 "\t [-z tos] IPv4-mcast-group\n" 199 #endif /* INET */ 200 #ifdef INET6 201 "\tping [-6AaDd" 202 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 203 "E" 204 #endif 205 "fHnNoOq" 206 #ifdef IPV6_USE_MIN_MTU 207 "u" 208 #endif 209 "vyY" 210 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 211 "Z" 212 #endif 213 "] " 214 "[-b bufsiz] [-c count] [-e gateway]\n" 215 "\t [-I interface] [-i wait] [-k addrtype] [-l preload] " 216 "[-m hoplimit]\n" 217 "\t [-p pattern]" 218 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 219 " [-P policy]" 220 #endif 221 " [-S sourceaddr] [-s packetsize] [-t timeout]\n" 222 "\t [-W waittime] [-z tclass] [IPv6-hops ...] IPv6-host\n" 223 #endif /* INET6 */ 224 ); 225 226 exit(1); 227 } 228