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 33 #include <arpa/inet.h> 34 #include <netinet/in.h> 35 #include <sys/types.h> 36 #include <sys/socket.h> 37 38 #include <err.h> 39 #include <errno.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdbool.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 /* 48 * Sends a single UDP packet to the provided address, with SO_DONTROUTE set 49 * I couldn't find a way to do this with builtin utilities like nc(1) 50 */ 51 int 52 main(int argc, char **argv) 53 { 54 struct sockaddr_storage dst; 55 int s, t; 56 int opt; 57 int ret; 58 ssize_t len; 59 const char* sendbuf = "Hello, World!"; 60 const size_t buflen = 80; 61 char recvbuf[buflen]; 62 bool v6 = false; 63 const char *addr, *tapdev; 64 const uint16_t port = 46120; 65 66 bzero(&dst, sizeof(dst)); 67 if (argc < 3 || argc > 4) { 68 fprintf(stderr, "Usage: %s [-6] ip_address tapdev\n", argv[0]); 69 exit(2); 70 } 71 72 if (strcmp("-6", argv[1]) == 0) { 73 v6 = true; 74 addr = argv[2]; 75 tapdev = argv[3]; 76 } else { 77 addr = argv[1]; 78 tapdev = argv[2]; 79 } 80 81 t = open(tapdev, O_RDWR | O_NONBLOCK); 82 if (t < 0) 83 err(EXIT_FAILURE, "open"); 84 85 if (v6) 86 s = socket(PF_INET6, SOCK_DGRAM, 0); 87 else 88 s = socket(PF_INET, SOCK_DGRAM, 0); 89 if (s < 0) 90 err(EXIT_FAILURE, "socket"); 91 opt = 1; 92 93 ret = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)); 94 if (ret == -1) 95 err(EXIT_FAILURE, "setsockopt(SO_DONTROUTE)"); 96 97 if (v6) { 98 struct sockaddr_in6 *dst6 = ((struct sockaddr_in6*)&dst); 99 100 dst.ss_len = sizeof(struct sockaddr_in6); 101 dst.ss_family = AF_INET6; 102 dst6->sin6_port = htons(port); 103 ret = inet_pton(AF_INET6, addr, &dst6->sin6_addr); 104 } else { 105 struct sockaddr_in *dst4 = ((struct sockaddr_in*)&dst); 106 107 dst.ss_len = sizeof(struct sockaddr_in); 108 dst.ss_family = AF_INET; 109 dst4->sin_port = htons(port); 110 ret = inet_pton(AF_INET, addr, &dst4->sin_addr); 111 } 112 if (ret != 1) 113 err(EXIT_FAILURE, "inet_pton returned %d", ret); 114 115 ret = sendto(s, sendbuf, strlen(sendbuf), 0, (struct sockaddr*)&dst, 116 dst.ss_len); 117 if (ret == -1) 118 err(EXIT_FAILURE, "sendto"); 119 120 /* Verify that the packet went to the desired tap device */ 121 122 len = read(t, recvbuf, buflen); 123 if (len == 0) 124 errx(EXIT_FAILURE, "read returned EOF"); 125 else if (len < 0 && errno == EAGAIN) 126 errx(EXIT_FAILURE, "Did not receive any packets"); 127 else if (len < 0) 128 err(EXIT_FAILURE, "read"); 129 130 /* 131 * If read returned anything at all, consider it a success. The packet 132 * should be an Ethernet frame containing an ARP request for 133 * ip_address. We won't bother to decode it 134 */ 135 return (0); 136 } 137