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