1 /* 2 * Copyright (c) 2016 Vincent Gross <vincent.gross@kilob.yt> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <err.h> 18 #include <errno.h> 19 #include <getopt.h> 20 #include <netdb.h> 21 #include <signal.h> 22 #include <stdlib.h> 23 #include <string.h> 24 #include <stdio.h> 25 #include <unistd.h> 26 27 #include <sys/socket.h> 28 #include <sys/types.h> 29 #include <sys/wait.h> 30 31 #include <netinet/in.h> 32 33 #include <arpa/inet.h> 34 35 #define PORTNUM "23000" 36 37 int 38 main(int argc, char *argv[]) 39 { 40 struct addrinfo hints; 41 struct addrinfo *in6ai; 42 43 struct sockaddr_in6 *null_sin6 = NULL; 44 struct sockaddr_in6 **next_sin6_p = NULL; 45 struct sockaddr_in6 **first_sin6p = &null_sin6; 46 struct sockaddr_in6 **bind_sin6p = &null_sin6; 47 struct sockaddr_in6 **sendmsg_sin6p = &null_sin6; 48 struct sockaddr_in6 **setsockopt_sin6p = &null_sin6; 49 struct sockaddr_in6 **dst_sin6p = &null_sin6; 50 51 int ch, rc, wstat, expected = -1; 52 int first_sock; 53 int reuse_addr = 0; 54 pid_t pid; 55 56 const char *numerr; 57 char adrbuf[40]; 58 const char *adrp; 59 60 61 bzero(&hints, sizeof(hints)); 62 hints.ai_family = AF_INET6; 63 hints.ai_socktype = SOCK_DGRAM; 64 65 do { 66 if (next_sin6_p == NULL) 67 next_sin6_p = malloc(sizeof(*next_sin6_p)); 68 if (next_sin6_p == NULL) 69 err(2, "malloc()"); 70 *next_sin6_p = NULL; 71 while ((ch = getopt(argc, argv, "dfbmoe:")) != -1) { 72 switch(ch) { 73 case 'd': 74 dst_sin6p = next_sin6_p; 75 break; 76 case 'f': 77 first_sin6p = next_sin6_p; 78 break; 79 case 'b': 80 bind_sin6p = next_sin6_p; 81 break; 82 case 'm': 83 sendmsg_sin6p = next_sin6_p; 84 break; 85 case 'o': 86 setsockopt_sin6p = next_sin6_p; 87 break; 88 case 'e': 89 expected = strtonum(optarg, 0, 255, &numerr); 90 if (numerr != NULL) 91 errx(2, "strtonum(%s): %s", optarg, numerr); 92 break; 93 } 94 } 95 if (optind < argc) { 96 rc = getaddrinfo(argv[optind], PORTNUM, &hints, &in6ai); 97 if (rc) 98 errx(2, "getaddrinfo(%s) = %d: %s", 99 argv[0], rc, gai_strerror(rc)); 100 *next_sin6_p = (struct sockaddr_in6 *)in6ai->ai_addr; 101 next_sin6_p = NULL; 102 } 103 optreset = 1; optind++; 104 } while (optind < argc); 105 106 if (*bind_sin6p == NULL) 107 errx(2, "bind_sin6p == NULL"); 108 109 if (*dst_sin6p == NULL) 110 errx(2, "dst_sin6p == NULL"); 111 112 if (expected < 0) 113 errx(2, "need expected"); 114 115 if (*first_sin6p) { 116 first_sock = udp6_first(*first_sin6p); 117 reuse_addr = 1; 118 } 119 120 pid = fork(); 121 if (pid == 0) { 122 return udp6_override(*dst_sin6p, *bind_sin6p, 123 *setsockopt_sin6p, *sendmsg_sin6p, reuse_addr); 124 } 125 (void)wait(&wstat); 126 127 if (*first_sin6p) 128 close(first_sock); 129 130 if (! WIFEXITED(wstat)) 131 errx(2, "error setting up override"); 132 133 if (WEXITSTATUS(wstat) != expected) 134 errx(2, "expected %d, got %d", expected, WEXITSTATUS(wstat)); 135 136 return EXIT_SUCCESS; 137 } 138 139 140 int 141 udp6_first(struct sockaddr_in6 *src) 142 { 143 int s_con; 144 145 s_con = socket(AF_INET6, SOCK_DGRAM, 0); 146 if (s_con == -1) 147 err(2, "udp6_bind: socket()"); 148 149 if (bind(s_con, (struct sockaddr *)src, src->sin6_len)) 150 err(2, "udp6_bind: bind()"); 151 152 return s_con; 153 } 154 155 156 int 157 udp6_override(struct sockaddr_in6 *dst, struct sockaddr_in6 *src_bind, 158 struct sockaddr_in6 *src_setsockopt, struct sockaddr_in6 *src_sendmsg, 159 int reuse_addr) 160 { 161 int s, optval, error, saved_errno; 162 ssize_t send_rc; 163 struct msghdr msg; 164 struct iovec iov; 165 struct cmsghdr *cmsg; 166 struct in6_pktinfo *pi_sendmsg; 167 struct in6_pktinfo pi_setsockopt; 168 union { 169 struct cmsghdr hdr; 170 unsigned char buf[CMSG_SPACE(sizeof(struct in6_pktinfo))]; 171 } cmsgbuf; 172 173 bzero(&msg, sizeof(msg)); 174 bzero(&cmsgbuf, sizeof(cmsgbuf)); 175 bzero(&pi_setsockopt, sizeof(pi_setsockopt)); 176 177 s = socket(AF_INET6, SOCK_DGRAM, 0); 178 if (s == -1) { 179 warn("udp6_override: socket()"); 180 kill(getpid(), SIGTERM); 181 } 182 183 if (reuse_addr) { 184 optval = 1; 185 if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int))) { 186 warn("udp6_override: setsockopt(SO_REUSEADDR)"); 187 kill(getpid(), SIGTERM); 188 } 189 } 190 191 if (bind(s, (struct sockaddr *)src_bind, src_bind->sin6_len)) { 192 warn("udp6_override: bind()"); 193 kill(getpid(), SIGTERM); 194 } 195 196 if (src_setsockopt != NULL) { 197 memcpy(&pi_setsockopt.ipi6_addr, &src_setsockopt->sin6_addr, sizeof(struct in6_addr)); 198 if (setsockopt(s, IPPROTO_IPV6, IPV6_PKTINFO, &pi_setsockopt, sizeof(pi_setsockopt))) { 199 warn("udp6_override: setsockopt(IPV6_PKTINFO)"); 200 kill(getpid(), SIGTERM); 201 } 202 } 203 204 iov.iov_base = "payload"; 205 iov.iov_len = 8; 206 msg.msg_name = dst; 207 msg.msg_namelen = dst->sin6_len; 208 msg.msg_iov = &iov; 209 msg.msg_iovlen = 1; 210 211 if (src_sendmsg) { 212 msg.msg_control = &cmsgbuf.buf; 213 msg.msg_controllen = sizeof(cmsgbuf.buf); 214 cmsg = CMSG_FIRSTHDR(&msg); 215 cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); 216 cmsg->cmsg_level = IPPROTO_IPV6; 217 cmsg->cmsg_type = IPV6_PKTINFO; 218 pi_sendmsg = (struct in6_pktinfo *)CMSG_DATA(cmsg); 219 memcpy(&pi_sendmsg->ipi6_addr, &src_sendmsg->sin6_addr, sizeof(struct in6_addr)); 220 } 221 222 send_rc = sendmsg(s, &msg, 0); 223 saved_errno = errno; 224 225 close(s); 226 227 if (send_rc == iov.iov_len) 228 return 0; 229 return saved_errno; 230 } 231