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