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
main(int argc,char * argv[])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
udp6_first(struct sockaddr_in6 * src)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
udp6_override(struct sockaddr_in6 * dst,struct sockaddr_in6 * src_bind,struct sockaddr_in6 * src_setsockopt,struct sockaddr_in6 * src_sendmsg,int reuse_addr)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