1 /* 2 * Copyright (c) 2014 Spectra Logic Corporation 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions, and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * substantially similar to the "NO WARRANTY" disclaimer below 13 * ("Disclaimer") and any redistribution must be conditioned upon 14 * including a substantially similar Disclaimer requirement for further 15 * binary redistribution. 16 * 17 * NO WARRANTY 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 27 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGES. 29 * 30 * Authors: Alan Somers (Spectra Logic Corporation) 31 * 32 * $FreeBSD$ 33 */ 34 35 #include <arpa/inet.h> 36 #include <netinet/in.h> 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 40 #include <err.h> 41 #include <errno.h> 42 #include <fcntl.h> 43 #include <stdio.h> 44 #include <stdbool.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 /* 50 * Sends a single UDP packet to the provided address, with SO_DONTROUTE set 51 * I couldn't find a way to do this with builtin utilities like nc(1) 52 */ 53 int 54 main(int argc, char **argv) 55 { 56 struct sockaddr_storage dst; 57 int s, t; 58 int opt; 59 int ret; 60 ssize_t len; 61 const char* sendbuf = "Hello, World!"; 62 const size_t buflen = 80; 63 char recvbuf[buflen]; 64 bool v6 = false; 65 const char *addr, *tapdev; 66 const uint16_t port = 46120; 67 68 bzero(&dst, sizeof(dst)); 69 if (argc < 3 || argc > 4) { 70 fprintf(stderr, "Usage: %s [-6] ip_address tapdev\n", argv[0]); 71 exit(2); 72 } 73 74 if (strcmp("-6", argv[1]) == 0) { 75 v6 = true; 76 addr = argv[2]; 77 tapdev = argv[3]; 78 } else { 79 addr = argv[1]; 80 tapdev = argv[2]; 81 } 82 83 t = open(tapdev, O_RDWR | O_NONBLOCK); 84 if (t < 0) 85 err(EXIT_FAILURE, "open"); 86 87 if (v6) 88 s = socket(PF_INET6, SOCK_DGRAM, 0); 89 else 90 s = socket(PF_INET, SOCK_DGRAM, 0); 91 if (s < 0) 92 err(EXIT_FAILURE, "socket"); 93 opt = 1; 94 95 ret = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)); 96 if (ret == -1) 97 err(EXIT_FAILURE, "setsockopt(SO_DONTROUTE)"); 98 99 if (v6) { 100 struct sockaddr_in6 *dst6 = ((struct sockaddr_in6*)&dst); 101 102 dst.ss_len = sizeof(struct sockaddr_in6); 103 dst.ss_family = AF_INET6; 104 dst6->sin6_port = htons(port); 105 ret = inet_pton(AF_INET6, addr, &dst6->sin6_addr); 106 } else { 107 struct sockaddr_in *dst4 = ((struct sockaddr_in*)&dst); 108 109 dst.ss_len = sizeof(struct sockaddr_in); 110 dst.ss_family = AF_INET; 111 dst4->sin_port = htons(port); 112 ret = inet_pton(AF_INET, addr, &dst4->sin_addr); 113 } 114 if (ret != 1) 115 err(EXIT_FAILURE, "inet_pton returned %d", ret); 116 117 ret = sendto(s, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&dst, 118 dst.ss_len); 119 if (ret == -1) 120 err(EXIT_FAILURE, "sendto"); 121 122 /* Verify that the packet went to the desired tap device */ 123 124 len = read(t, recvbuf, buflen); 125 if (len == 0) 126 errx(EXIT_FAILURE, "read returned EOF"); 127 else if (len < 0 && errno == EAGAIN) 128 errx(EXIT_FAILURE, "Did not receive any packets"); 129 else if (len < 0) 130 err(EXIT_FAILURE, "read"); 131 132 /* 133 * If read returned anything at all, consider it a success. The packet 134 * should be an Ethernet frame containing an ARP request for 135 * ip_address. We won't bother to decode it 136 */ 137 return (0); 138 } 139