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