1/*	$OpenBSD: nonxt-reflect.c,v 1.2 2018/05/21 01:19:21 bluhm Exp $	*/
2/*
3 * Copyright (c) Alexander Bluhm <bluhm@genua.de>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#include <sys/types.h>
19#include <sys/socket.h>
20
21#include <netdb.h>
22
23#include <err.h>
24#include <errno.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <unistd.h>
29
30void __dead usage(void);
31
32void
33usage(void)
34{
35	fprintf(stderr, "usage: nonxt-reflect localaddr\n"
36	    "Daemonize, wait for protocol 59 packets, and answer them.\n");
37	exit(1);
38}
39
40int
41main(int argc, char *argv[])
42{
43	struct addrinfo hints, *res, *res0;
44	const char *cause = NULL, *local;
45	int error;
46	int save_errno;
47	int s;
48	char buf[1024];
49
50	switch (argc) {
51	case 2:
52		local = argv[1];
53		break;
54	default:
55		usage();
56	}
57
58	if (pledge("stdio inet dns proc", NULL) == -1)
59		err(1, "pledge");
60
61	/* Create socket and bind it to local address. */
62	memset(&hints, 0, sizeof(hints));
63	hints.ai_family = AF_UNSPEC;
64	hints.ai_socktype = SOCK_RAW;
65	hints.ai_protocol = IPPROTO_NONE;
66	hints.ai_flags = AI_PASSIVE;
67	error = getaddrinfo(local, NULL, &hints, &res0);
68	if (error)
69		errx(1, "getaddrinfo local: %s", gai_strerror(error));
70	for (res = res0; res; res = res->ai_next) {
71		s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
72		if (s == -1) {
73			cause = "socket";
74			continue;
75		}
76		if (bind(s, res->ai_addr, res->ai_addrlen) == -1) {
77			cause = "bind";
78			save_errno = errno;
79			close(s);
80			errno = save_errno;
81			continue;
82		}
83		break;
84	}
85	if (res == NULL)
86		err(1, "%s", cause);
87	freeaddrinfo(res0);
88
89	/* Socket is ready to receive, parent process may proceed. */
90	daemon(1, 1);
91	if (pledge("stdio inet", NULL) == -1)
92		err(1, "pledge");
93
94	for (;;) {
95		struct sockaddr_storage ss;
96		socklen_t slen;
97
98		/* Receive a protocol 59 packet. */
99		slen = sizeof(ss);
100		if (recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *)&ss,
101		    &slen) == -1)
102			err(1, "recv");
103		/* Send back a reply packet. */
104		if (sendto(s, buf, 0, 0, (struct sockaddr *)&ss, slen) == -1)
105			err(1, "send");
106	}
107
108	/* NOTREACHED */
109	return 0;
110}
111