1 /* 2 * main.c 3 * 4 * Copyright (c) 1996-1999 Whistle Communications, Inc. 5 * All rights reserved. 6 * 7 * Subject to the following obligations and disclaimer of warranty, use and 8 * redistribution of this software, in source or object code forms, with or 9 * without modifications are expressly permitted by Whistle Communications; 10 * provided, however, that: 11 * 1. Any and all reproductions of the source or object code must include the 12 * copyright notice above and the following disclaimer of warranties; and 13 * 2. No rights are granted, in any manner or form, to use Whistle 14 * Communications, Inc. trademarks, including the mark "WHISTLE 15 * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 16 * such appears in the above copyright notice or in the software. 17 * 18 * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 19 * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 20 * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 21 * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 22 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 23 * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 24 * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 25 * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 26 * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 27 * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 28 * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 29 * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 30 * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 31 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 32 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 33 * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 34 * OF SUCH DAMAGE. 35 * 36 * $Whistle: main.c,v 1.9 1999/01/20 00:26:26 archie Exp $ 37 */ 38 39 #include <sys/cdefs.h> 40 __FBSDID("$FreeBSD$"); 41 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <ctype.h> 46 #include <unistd.h> 47 #include <sysexits.h> 48 #include <errno.h> 49 #include <err.h> 50 #include <stringlist.h> 51 52 #include <sys/types.h> 53 #include <sys/socket.h> 54 #include <sys/select.h> 55 56 #include <netgraph.h> 57 58 #define DEFAULT_HOOKNAME "debug" 59 #define NG_SOCK_HOOK_NAME "hook" 60 61 #define BUF_SIZE (64 * 1024) 62 63 static void WriteAscii(u_char * buf, int len); 64 static void Usage(void); 65 static void send_msgs(int, const char *); 66 67 static int outfd = STDOUT_FILENO; 68 static int infd = STDIN_FILENO; 69 70 static StringList *msgs; 71 72 /* 73 * main() 74 */ 75 int 76 main(int ac, char *av[]) 77 { 78 struct ngm_connect ngc; 79 const char *path = NULL; 80 const char *hook = DEFAULT_HOOKNAME; 81 int csock, dsock; 82 int asciiFlag = 0; 83 int loopFlag = 0; 84 int noInput = 0; 85 int execFlag = 0; 86 int ch; 87 88 if ((msgs = sl_init()) == NULL) 89 err(EX_OSERR, NULL); 90 91 /* Parse flags */ 92 while ((ch = getopt(ac, av, "aedlm:nsS")) != -1) { 93 switch (ch) { 94 case 'a': 95 asciiFlag = 1; 96 break; 97 case 'd': 98 NgSetDebug(NgSetDebug(-1) + 1); 99 break; 100 case 'e': 101 execFlag = 1; 102 break; 103 case 'l': 104 loopFlag = 1; 105 break; 106 case 'n': 107 noInput = 1; 108 break; 109 case 'm': 110 if (sl_add(msgs, optarg) == -1) 111 err(EX_OSERR, NULL); 112 break; 113 case 's': 114 outfd = STDIN_FILENO; 115 break; 116 case 'S': 117 infd = STDOUT_FILENO; 118 break; 119 case '?': 120 default: 121 Usage(); 122 } 123 } 124 ac -= optind; 125 av += optind; 126 127 if (execFlag) { 128 if (asciiFlag || loopFlag) { 129 fprintf(stderr, "conflicting options\n"); 130 Usage(); 131 } 132 if (ac < 3) 133 Usage(); 134 path = av[0]; 135 hook = av[1]; 136 av += 2; 137 ac -= 2; 138 } else { 139 /* Get params */ 140 switch (ac) { 141 case 2: 142 hook = av[1]; 143 /* FALLTHROUGH */ 144 case 1: 145 path = av[0]; 146 break; 147 default: 148 Usage(); 149 } 150 } 151 152 /* Get sockets */ 153 if (NgMkSockNode(NULL, &csock, &dsock) < 0) 154 errx(EX_OSERR, "can't get sockets"); 155 156 /* Connect socket node to specified node */ 157 snprintf(ngc.path, sizeof(ngc.path), "%s", path); 158 snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME); 159 snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook); 160 161 if (NgSendMsg(csock, ".", 162 NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0) 163 errx(EX_OSERR, "can't connect to node"); 164 165 if (execFlag) { 166 /* move dsock to fd 0 and 1 */ 167 (void)close(0); 168 (void)close(1); 169 if (!noInput) 170 (void)dup2(dsock, 0); 171 (void)dup2(dsock, 1); 172 173 send_msgs(csock, path); 174 175 /* try executing the program */ 176 (void)execv(av[0], av); 177 err(EX_OSERR, "%s", av[0]); 178 179 } else 180 send_msgs(csock, path); 181 182 /* Close standard input if not reading from it */ 183 if (noInput) 184 fclose(stdin); 185 186 /* Relay data */ 187 while (1) { 188 fd_set rfds; 189 190 /* Setup bits */ 191 FD_ZERO(&rfds); 192 if (!noInput) 193 FD_SET(infd, &rfds); 194 FD_SET(dsock, &rfds); 195 196 /* Wait for something to happen */ 197 if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) 198 err(EX_OSERR, "select"); 199 200 /* Check data from socket */ 201 if (FD_ISSET(dsock, &rfds)) { 202 char buf[BUF_SIZE]; 203 int rl, wl; 204 205 /* Read packet from socket */ 206 if ((rl = NgRecvData(dsock, 207 buf, sizeof(buf), NULL)) < 0) 208 err(EX_OSERR, "read(hook)"); 209 if (rl == 0) 210 errx(EX_OSERR, "read EOF from hook?!"); 211 212 /* Write packet to stdout */ 213 if (asciiFlag) 214 WriteAscii((u_char *) buf, rl); 215 else if ((wl = write(outfd, buf, rl)) != rl) { 216 if (wl < 0) { 217 err(EX_OSERR, "write(stdout)"); 218 } else { 219 errx(EX_OSERR, 220 "stdout: read %d, wrote %d", 221 rl, wl); 222 } 223 } 224 /* Loopback */ 225 if (loopFlag) { 226 if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) 227 err(EX_OSERR, "write(hook)"); 228 } 229 } 230 231 /* Check data from stdin */ 232 if (FD_ISSET(infd, &rfds)) { 233 char buf[BUF_SIZE]; 234 int rl; 235 236 /* Read packet from stdin */ 237 if ((rl = read(infd, buf, sizeof(buf))) < 0) 238 err(EX_OSERR, "read(stdin)"); 239 if (rl == 0) 240 errx(EX_OSERR, "EOF(stdin)"); 241 242 /* Write packet to socket */ 243 if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) 244 err(EX_OSERR, "write(hook)"); 245 } 246 } 247 } 248 249 /* 250 * Dump data in hex and ASCII form 251 */ 252 static void 253 WriteAscii(u_char *buf, int len) 254 { 255 char ch, sbuf[100]; 256 int k, count; 257 258 for (count = 0; count < len; count += 16) { 259 snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 260 for (k = 0; k < 16; k++) 261 if (count + k < len) 262 snprintf(sbuf + strlen(sbuf), 263 sizeof(sbuf) - strlen(sbuf), 264 "%02x ", buf[count + k]); 265 else 266 snprintf(sbuf + strlen(sbuf), 267 sizeof(sbuf) - strlen(sbuf), " "); 268 snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 269 for (k = 0; k < 16; k++) 270 if (count + k < len) { 271 ch = isprint(buf[count + k]) ? 272 buf[count + k] : '.'; 273 snprintf(sbuf + strlen(sbuf), 274 sizeof(sbuf) - strlen(sbuf), "%c", ch); 275 } else 276 snprintf(sbuf + strlen(sbuf), 277 sizeof(sbuf) - strlen(sbuf), " "); 278 snprintf(sbuf + strlen(sbuf), 279 sizeof(sbuf) - strlen(sbuf), "\n"); 280 (void) write(outfd, sbuf, strlen(sbuf)); 281 } 282 ch = '\n'; 283 write(outfd, &ch, 1); 284 } 285 286 /* 287 * Display usage and exit 288 */ 289 static void 290 Usage(void) 291 { 292 fprintf(stderr, "usage: nghook [-adlnsS] path [hookname]\n"); 293 fprintf(stderr, " or: nghook -e [-n] [-m msg]* path hookname prog " 294 "[args...]\n"); 295 exit(EX_USAGE); 296 } 297 298 /* 299 * Send the messages to the node 300 */ 301 static void 302 send_msgs(int cs, const char *path) 303 { 304 u_int i; 305 306 for (i = 0; i < msgs->sl_cur; i++) 307 if (NgSendAsciiMsg(cs, path, "%s", msgs->sl_str[i]) == -1) 308 err(EX_OSERR, "sending message '%s'", msgs->sl_str[i]); 309 } 310