1*d6191a09Sbluhm /* $OpenBSD: rip6cksum.c,v 1.1.1.1 2019/05/09 15:54:31 bluhm Exp $ */
2*d6191a09Sbluhm /*
3*d6191a09Sbluhm * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
4*d6191a09Sbluhm *
5*d6191a09Sbluhm * Permission to use, copy, modify, and distribute this software for any
6*d6191a09Sbluhm * purpose with or without fee is hereby granted, provided that the above
7*d6191a09Sbluhm * copyright notice and this permission notice appear in all copies.
8*d6191a09Sbluhm *
9*d6191a09Sbluhm * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10*d6191a09Sbluhm * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*d6191a09Sbluhm * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12*d6191a09Sbluhm * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*d6191a09Sbluhm * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*d6191a09Sbluhm * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15*d6191a09Sbluhm * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*d6191a09Sbluhm */
17*d6191a09Sbluhm
18*d6191a09Sbluhm #include <errno.h>
19*d6191a09Sbluhm #include <err.h>
20*d6191a09Sbluhm #include <limits.h>
21*d6191a09Sbluhm #include <stdio.h>
22*d6191a09Sbluhm #include <stdlib.h>
23*d6191a09Sbluhm #include <string.h>
24*d6191a09Sbluhm #include <unistd.h>
25*d6191a09Sbluhm
26*d6191a09Sbluhm #include <netinet/in.h>
27*d6191a09Sbluhm
28*d6191a09Sbluhm #include <sys/select.h>
29*d6191a09Sbluhm #include <sys/socket.h>
30*d6191a09Sbluhm #include <sys/wait.h>
31*d6191a09Sbluhm
32*d6191a09Sbluhm void __dead usage(void);
33*d6191a09Sbluhm
34*d6191a09Sbluhm void __dead
usage(void)35*d6191a09Sbluhm usage(void)
36*d6191a09Sbluhm {
37*d6191a09Sbluhm fprintf(stderr, "rip6cksum [-ehw] [-c ckoff] [-r recvsz] [-s sendsz] "
38*d6191a09Sbluhm "[-- scapy ...]\n"
39*d6191a09Sbluhm " -c ckoff set checksum offset within rip header\n"
40*d6191a09Sbluhm " -e expect error when setting ckoff\n"
41*d6191a09Sbluhm " -h help, show usage\n"
42*d6191a09Sbluhm " -r recvsz expected payload size from socket\n"
43*d6191a09Sbluhm " -s sendsz send payload of given size to socket\n"
44*d6191a09Sbluhm " -w wait for packet on socket, timeout 10 seconds\n"
45*d6191a09Sbluhm " scapy ... run scapy program after socket setup\n"
46*d6191a09Sbluhm );
47*d6191a09Sbluhm exit(1);
48*d6191a09Sbluhm }
49*d6191a09Sbluhm
50*d6191a09Sbluhm const struct in6_addr loop6 = IN6ADDR_LOOPBACK_INIT;
51*d6191a09Sbluhm int
main(int argc,char * argv[])52*d6191a09Sbluhm main(int argc, char *argv[])
53*d6191a09Sbluhm {
54*d6191a09Sbluhm int s, ch, eflag, cflag, rflag, sflag, wflag;
55*d6191a09Sbluhm int ckoff;
56*d6191a09Sbluhm size_t recvsz, sendsz;
57*d6191a09Sbluhm const char *errstr;
58*d6191a09Sbluhm struct sockaddr_in6 sin6;
59*d6191a09Sbluhm
60*d6191a09Sbluhm if (setvbuf(stdout, NULL, _IOLBF, 0) != 0)
61*d6191a09Sbluhm err(1, "setvbuf stdout line buffered");
62*d6191a09Sbluhm
63*d6191a09Sbluhm eflag = cflag = rflag = sflag = wflag = 0;
64*d6191a09Sbluhm while ((ch = getopt(argc, argv, "c:ehr:s:w")) != -1) {
65*d6191a09Sbluhm switch (ch) {
66*d6191a09Sbluhm case 'c':
67*d6191a09Sbluhm ckoff = strtonum(optarg, INT_MIN, INT_MAX, &errstr);
68*d6191a09Sbluhm if (errstr != NULL)
69*d6191a09Sbluhm errx(1, "ckoff is %s: %s", errstr, optarg);
70*d6191a09Sbluhm cflag = 1;
71*d6191a09Sbluhm break;
72*d6191a09Sbluhm case 'e':
73*d6191a09Sbluhm eflag = 1;
74*d6191a09Sbluhm break;
75*d6191a09Sbluhm case 'r':
76*d6191a09Sbluhm recvsz = strtonum(optarg, 0, INT_MAX, &errstr);
77*d6191a09Sbluhm if (errstr != NULL)
78*d6191a09Sbluhm errx(1, "recvsz is %s: %s", errstr, optarg);
79*d6191a09Sbluhm rflag = 1;
80*d6191a09Sbluhm break;
81*d6191a09Sbluhm case 's':
82*d6191a09Sbluhm sendsz = strtonum(optarg, 0, INT_MAX, &errstr);
83*d6191a09Sbluhm if (errstr != NULL)
84*d6191a09Sbluhm errx(1, "sendsz is %s: %s", errstr, optarg);
85*d6191a09Sbluhm sflag = 1;
86*d6191a09Sbluhm break;
87*d6191a09Sbluhm case 'w':
88*d6191a09Sbluhm wflag = 1;
89*d6191a09Sbluhm break;
90*d6191a09Sbluhm default:
91*d6191a09Sbluhm usage();
92*d6191a09Sbluhm }
93*d6191a09Sbluhm }
94*d6191a09Sbluhm argc -= optind;
95*d6191a09Sbluhm argv += optind;
96*d6191a09Sbluhm
97*d6191a09Sbluhm printf("socket inet6 raw 255\n");
98*d6191a09Sbluhm s = socket(AF_INET6, SOCK_RAW, 255);
99*d6191a09Sbluhm if (s == -1)
100*d6191a09Sbluhm err(1, "socket raw");
101*d6191a09Sbluhm memset(&sin6, 0, sizeof(sin6));
102*d6191a09Sbluhm sin6.sin6_family = AF_INET6;
103*d6191a09Sbluhm sin6.sin6_addr = loop6;
104*d6191a09Sbluhm printf("bind ::1\n");
105*d6191a09Sbluhm if (bind(s, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
106*d6191a09Sbluhm err(1, "bind ::1");
107*d6191a09Sbluhm printf("connect ::1\n");
108*d6191a09Sbluhm if (connect(s, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
109*d6191a09Sbluhm err(1, "connect ::1");
110*d6191a09Sbluhm
111*d6191a09Sbluhm if (cflag) {
112*d6191a09Sbluhm printf("setsockopt ipv6 checksum %d\n", ckoff);
113*d6191a09Sbluhm if (setsockopt(s, IPPROTO_IPV6, IPV6_CHECKSUM, &ckoff,
114*d6191a09Sbluhm sizeof(ckoff)) == -1) {
115*d6191a09Sbluhm if (!eflag)
116*d6191a09Sbluhm err(1, "setsockopt ckoff");
117*d6191a09Sbluhm printf("setsockopt failed as expected: %s\n",
118*d6191a09Sbluhm strerror(errno));
119*d6191a09Sbluhm } else {
120*d6191a09Sbluhm if (eflag)
121*d6191a09Sbluhm errx(1, "setsockopt succeeded unexpectedly");
122*d6191a09Sbluhm }
123*d6191a09Sbluhm }
124*d6191a09Sbluhm
125*d6191a09Sbluhm if (argc) {
126*d6191a09Sbluhm pid_t pid;
127*d6191a09Sbluhm
128*d6191a09Sbluhm printf("fork child process\n");
129*d6191a09Sbluhm pid = fork();
130*d6191a09Sbluhm if (pid == -1)
131*d6191a09Sbluhm err(1, "fork");
132*d6191a09Sbluhm if (pid == 0) {
133*d6191a09Sbluhm /* child */
134*d6191a09Sbluhm printf("execute %s\n", argv[0]);
135*d6191a09Sbluhm execvp(argv[0], argv);
136*d6191a09Sbluhm err(1, "execvp %s", argv[0]);
137*d6191a09Sbluhm }
138*d6191a09Sbluhm printf("child pid %d\n", pid);
139*d6191a09Sbluhm }
140*d6191a09Sbluhm
141*d6191a09Sbluhm if (wflag) {
142*d6191a09Sbluhm int n;
143*d6191a09Sbluhm ssize_t r;
144*d6191a09Sbluhm size_t rsz;
145*d6191a09Sbluhm fd_set fds;
146*d6191a09Sbluhm struct timeval to;
147*d6191a09Sbluhm char buf[1<<16];
148*d6191a09Sbluhm
149*d6191a09Sbluhm FD_ZERO(&fds);
150*d6191a09Sbluhm FD_SET(s, &fds);
151*d6191a09Sbluhm to.tv_sec = 10;
152*d6191a09Sbluhm to.tv_usec = 0;
153*d6191a09Sbluhm printf("select socket read\n");
154*d6191a09Sbluhm n = select(s + 1, &fds, NULL, NULL, &to);
155*d6191a09Sbluhm switch (n) {
156*d6191a09Sbluhm case -1:
157*d6191a09Sbluhm err(1, "select");
158*d6191a09Sbluhm case 0:
159*d6191a09Sbluhm errx(1, "timeout");
160*d6191a09Sbluhm default:
161*d6191a09Sbluhm printf("selected %d\n", n);
162*d6191a09Sbluhm }
163*d6191a09Sbluhm printf("recv packet\n");
164*d6191a09Sbluhm r = recv(s, buf, sizeof(buf), 0);
165*d6191a09Sbluhm if (r < 0)
166*d6191a09Sbluhm err(1, "recv");
167*d6191a09Sbluhm rsz = r;
168*d6191a09Sbluhm printf("received payload size %zd\n", rsz);
169*d6191a09Sbluhm if (rflag) {
170*d6191a09Sbluhm if (rsz != recvsz)
171*d6191a09Sbluhm errx(1, "wrong payload size, expected %zu", recvsz);
172*d6191a09Sbluhm }
173*d6191a09Sbluhm }
174*d6191a09Sbluhm
175*d6191a09Sbluhm if (sflag) {
176*d6191a09Sbluhm size_t i;
177*d6191a09Sbluhm char *buf;
178*d6191a09Sbluhm
179*d6191a09Sbluhm buf = malloc(sendsz);
180*d6191a09Sbluhm if (buf == NULL)
181*d6191a09Sbluhm err(1, "malloc sendsz");
182*d6191a09Sbluhm for (i = 0; i < sendsz; i++)
183*d6191a09Sbluhm buf[i] = i & 0xff;
184*d6191a09Sbluhm printf("send payload of size %zu\n", sendsz);
185*d6191a09Sbluhm if (send(s, buf, sendsz, 0) == -1)
186*d6191a09Sbluhm err(1, "send");
187*d6191a09Sbluhm free(buf);
188*d6191a09Sbluhm }
189*d6191a09Sbluhm
190*d6191a09Sbluhm if (argc) {
191*d6191a09Sbluhm int status;
192*d6191a09Sbluhm
193*d6191a09Sbluhm printf("wait for child\n");
194*d6191a09Sbluhm if (wait(&status) == -1)
195*d6191a09Sbluhm err(1, "wait");
196*d6191a09Sbluhm if (status != 0)
197*d6191a09Sbluhm errx(1, "child program %s status %d", argv[0], status);
198*d6191a09Sbluhm printf("child program %s status %d\n", argv[0], status);
199*d6191a09Sbluhm }
200*d6191a09Sbluhm
201*d6191a09Sbluhm return 0;
202*d6191a09Sbluhm }
203