1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2023 Igor Ostapenko <pm@igoro.pro> 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 /* Used by divert(4) related tests */ 29 30 #include <errno.h> 31 #include <stdlib.h> 32 #include <stdbool.h> 33 #include <err.h> 34 #include <sysexits.h> 35 #include <string.h> 36 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <netinet/in.h> 40 #include <netinet/ip.h> 41 42 43 struct context { 44 unsigned short divert_port; 45 bool divert_back; 46 47 int fd; 48 struct sockaddr_in sin; 49 socklen_t sin_len; 50 char pkt[IP_MAXPACKET]; 51 ssize_t pkt_n; 52 }; 53 54 static void 55 init(struct context *c) 56 { 57 c->fd = socket(PF_DIVERT, SOCK_RAW, 0); 58 if (c->fd == -1) 59 errx(EX_OSERR, "init: Cannot create divert socket."); 60 61 memset(&c->sin, 0, sizeof(c->sin)); 62 c->sin.sin_family = AF_INET; 63 c->sin.sin_port = htons(c->divert_port); 64 c->sin.sin_addr.s_addr = INADDR_ANY; 65 c->sin_len = sizeof(struct sockaddr_in); 66 67 if (bind(c->fd, (struct sockaddr *) &c->sin, c->sin_len) != 0) 68 errx(EX_OSERR, "init: Cannot bind divert socket."); 69 } 70 71 static ssize_t 72 recv_pkt(struct context *c) 73 { 74 fd_set readfds; 75 struct timeval timeout; 76 int s; 77 78 FD_ZERO(&readfds); 79 FD_SET(c->fd, &readfds); 80 timeout.tv_sec = 3; 81 timeout.tv_usec = 0; 82 83 s = select(c->fd + 1, &readfds, 0, 0, &timeout); 84 if (s == -1) 85 errx(EX_IOERR, "recv_pkt: select() errors."); 86 if (s != 1) /* timeout */ 87 return (-1); 88 89 c->pkt_n = recvfrom(c->fd, c->pkt, sizeof(c->pkt), 0, 90 (struct sockaddr *) &c->sin, &c->sin_len); 91 if (c->pkt_n == -1) 92 errx(EX_IOERR, "recv_pkt: recvfrom() errors."); 93 94 return (c->pkt_n); 95 } 96 97 static void 98 send_pkt(struct context *c) 99 { 100 ssize_t n; 101 102 n = sendto(c->fd, c->pkt, c->pkt_n, 0, 103 (struct sockaddr *) &c->sin, c->sin_len); 104 if (n == -1) 105 err(EX_IOERR, "send_pkt: sendto() errors"); 106 if (n != c->pkt_n) 107 errx(EX_IOERR, "send_pkt: sendto() sent %zd of %zd bytes.", 108 n, c->pkt_n); 109 } 110 111 int 112 main(int argc, char *argv[]) 113 { 114 struct context c; 115 int npkt; 116 117 if (argc < 2) 118 errx(EX_USAGE, 119 "Usage: %s <divert-port> [divert-back]", argv[0]); 120 121 memset(&c, 0, sizeof(struct context)); 122 123 c.divert_port = (unsigned short) strtol(argv[1], NULL, 10); 124 if (c.divert_port == 0) 125 errx(EX_USAGE, "divert port is not defined."); 126 127 if (argc >= 3 && strcmp(argv[2], "divert-back") == 0) 128 c.divert_back = true; 129 130 131 init(&c); 132 133 npkt = 0; 134 while (recv_pkt(&c) > 0) { 135 if (c.divert_back) 136 send_pkt(&c); 137 npkt++; 138 if (npkt >= 10) 139 break; 140 } 141 142 if (npkt != 1) 143 errx(EXIT_FAILURE, "%d: npkt=%d.", c.divert_port, npkt); 144 145 return (EXIT_SUCCESS); 146 } 147