1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 __FBSDID("$FreeBSD$"); 31 32 #include <sys/types.h> 33 #include <sys/socket.h> 34 35 #include <arpa/inet.h> 36 #include <netdb.h> 37 #include <netinet/in.h> 38 39 #include <err.h> 40 #include <stdbool.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #include "main.h" 47 #ifdef INET 48 #include "ping.h" 49 #endif 50 #ifdef INET6 51 #include "ping6.h" 52 #endif 53 54 #if defined(INET) && defined(INET6) 55 #define OPTSTR PING6OPTS PING4OPTS 56 #elif defined(INET) 57 #define OPTSTR PING4OPTS 58 #elif defined(INET6) 59 #define OPTSTR PING6OPTS 60 #else 61 #error At least one of INET and INET6 is required 62 #endif 63 64 int 65 main(int argc, char *argv[]) 66 { 67 #if defined(INET) && defined(INET6) 68 struct in_addr a; 69 struct in6_addr a6; 70 #endif 71 #if defined(INET) || defined(INET6) 72 struct addrinfo hints; 73 #endif 74 int ch; 75 #ifdef INET 76 bool ipv4 = false; 77 #endif 78 #ifdef INET6 79 bool ipv6 = false; 80 81 if (strcmp(getprogname(), "ping6") == 0) 82 ipv6 = true; 83 #endif 84 85 while ((ch = getopt(argc, argv, ":" OPTSTR)) != -1) { 86 switch(ch) { 87 #ifdef INET 88 case '4': 89 ipv4 = true; 90 break; 91 #endif 92 #ifdef INET6 93 case '6': 94 ipv6 = true; 95 break; 96 #endif 97 #if defined(INET) && defined(INET6) 98 case 'S': 99 /* 100 * If -S is given with a numeric parameter, 101 * force use of the corresponding version. 102 */ 103 if (inet_pton(AF_INET, optarg, &a) == 1) 104 ipv4 = true; 105 else if (inet_pton(AF_INET6, optarg, &a) == 1) 106 ipv6 = true; 107 break; 108 #endif 109 default: 110 break; 111 } 112 } 113 114 if (optind >= argc) 115 usage(); 116 117 optreset = 1; 118 optind = 1; 119 #if defined(INET) && defined(INET6) 120 if (ipv4 && ipv6) 121 errx(1, "-4 and -6 cannot be used simultaneously"); 122 #endif 123 124 #if defined(INET) && defined(INET6) 125 if (inet_pton(AF_INET, argv[argc - 1], &a) == 1) { 126 if (ipv6) 127 errx(1, "IPv6 requested but IPv4 target address " 128 "provided"); 129 hints.ai_family = AF_INET; 130 } 131 else if (inet_pton(AF_INET6, argv[argc - 1], &a6) == 1) { 132 if (ipv4) 133 errx(1, "IPv4 requested but IPv6 target address " 134 "provided"); 135 hints.ai_family = AF_INET6; 136 } else if (ipv6) 137 hints.ai_family = AF_INET6; 138 else if (ipv4) 139 hints.ai_family = AF_INET; 140 else { 141 if (!feature_present("inet6")) 142 hints.ai_family = AF_INET; 143 else if (!feature_present("inet")) 144 hints.ai_family = AF_INET6; 145 else { 146 struct addrinfo *res; 147 148 memset(&hints, 0, sizeof(hints)); 149 hints.ai_socktype = SOCK_RAW; 150 hints.ai_family = AF_UNSPEC; 151 getaddrinfo(argv[argc - 1], NULL, &hints, &res); 152 if (res != NULL) { 153 hints.ai_family = res[0].ai_family; 154 freeaddrinfo(res); 155 } 156 } 157 } 158 #elif defined(INET) 159 hints.ai_family = AF_INET; 160 #elif defined(INET6) 161 hints.ai_family = AF_INET6; 162 #endif 163 164 #ifdef INET 165 if (hints.ai_family == AF_INET) 166 return ping(argc, argv); 167 #endif /* INET */ 168 #ifdef INET6 169 if (hints.ai_family == AF_INET6) 170 return ping6(argc, argv); 171 #endif /* INET6 */ 172 errx(1, "Unknown host"); 173 } 174 175 void 176 usage(void) 177 { 178 (void)fprintf(stderr, 179 "usage:\n" 180 #ifdef INET 181 "\tping [-4AaDdfHnoQqRrv] [-C pcp] [-c count] " 182 "[-G sweepmaxsize]\n" 183 " [-g sweepminsize] [-h sweepincrsize] [-i wait] " 184 "[-l preload]\n" 185 " [-M mask | time] [-m ttl] " 186 #ifdef IPSEC 187 "[-P policy] " 188 #endif 189 "[-p pattern] [-S src_addr] \n" 190 " [-s packetsize] [-t timeout] [-W waittime] [-z tos] " 191 "IPv4-host\n" 192 "\tping [-4AaDdfHLnoQqRrv] [-C pcp] [-c count] [-I iface] " 193 "[-i wait]\n" 194 " [-l preload] [-M mask | time] [-m ttl] " 195 #ifdef IPSEC 196 "[-P policy] " 197 #endif 198 "[-p pattern]\n" 199 " [-S src_addr] [-s packetsize] [-T ttl] [-t timeout] [-W waittime]\n" 200 " [-z tos] IPv4-mcast-group\n" 201 #endif /* INET */ 202 #ifdef INET6 203 "\tping [-6AaDd" 204 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 205 "E" 206 #endif 207 "fHnNoOq" 208 #ifdef IPV6_USE_MIN_MTU 209 "u" 210 #endif 211 "vyY" 212 #if defined(IPSEC) && !defined(IPSEC_POLICY_IPSEC) 213 "Z" 214 #endif 215 "] " 216 "[-b bufsiz] [-c count] [-e gateway]\n" 217 " [-I interface] [-i wait] [-k addrtype] [-l preload] " 218 "[-m hoplimit]\n" 219 " [-p pattern]" 220 #if defined(IPSEC) && defined(IPSEC_POLICY_IPSEC) 221 " [-P policy]" 222 #endif 223 " [-S sourceaddr] [-s packetsize] [-t timeout]\n" 224 " [-W waittime] [-z tclass] [IPv6-hops ...] IPv6-host\n" 225 #endif /* INET6 */ 226 ); 227 228 exit(1); 229 } 230