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 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 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