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 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <ctype.h> 44 #include <unistd.h> 45 #include <sysexits.h> 46 #include <errno.h> 47 #include <err.h> 48 #include <stringlist.h> 49 50 #include <sys/types.h> 51 #include <sys/socket.h> 52 #include <sys/select.h> 53 54 #include <netgraph.h> 55 56 #define DEFAULT_HOOKNAME "debug" 57 #define NG_SOCK_HOOK_NAME "hook" 58 59 #define BUF_SIZE (64 * 1024) 60 61 static void WriteAscii(u_char * buf, int len); 62 static void Usage(void); 63 static void send_msgs(int, const char *); 64 65 static int outfd = STDOUT_FILENO; 66 static int infd = STDIN_FILENO; 67 68 static StringList *msgs; 69 70 /* 71 * main() 72 */ 73 int 74 main(int ac, char *av[]) 75 { 76 struct ngm_connect ngc; 77 const char *path = NULL; 78 const char *hook = DEFAULT_HOOKNAME; 79 int csock, dsock; 80 int asciiFlag = 0; 81 int loopFlag = 0; 82 int noInput = 0; 83 int execFlag = 0; 84 int ch; 85 86 if ((msgs = sl_init()) == NULL) 87 err(EX_OSERR, NULL); 88 89 /* Parse flags */ 90 while ((ch = getopt(ac, av, "aedlm:nsS")) != -1) { 91 switch (ch) { 92 case 'a': 93 asciiFlag = 1; 94 break; 95 case 'd': 96 NgSetDebug(NgSetDebug(-1) + 1); 97 break; 98 case 'e': 99 execFlag = 1; 100 break; 101 case 'l': 102 loopFlag = 1; 103 break; 104 case 'n': 105 noInput = 1; 106 break; 107 case 'm': 108 if (sl_add(msgs, optarg) == -1) 109 err(EX_OSERR, NULL); 110 break; 111 case 's': 112 outfd = STDIN_FILENO; 113 break; 114 case 'S': 115 infd = STDOUT_FILENO; 116 break; 117 case '?': 118 default: 119 Usage(); 120 } 121 } 122 ac -= optind; 123 av += optind; 124 125 if (execFlag) { 126 if (asciiFlag || loopFlag) { 127 fprintf(stderr, "conflicting options\n"); 128 Usage(); 129 } 130 if (ac < 3) 131 Usage(); 132 path = av[0]; 133 hook = av[1]; 134 av += 2; 135 ac -= 2; 136 } else { 137 /* Get params */ 138 switch (ac) { 139 case 2: 140 hook = av[1]; 141 /* FALLTHROUGH */ 142 case 1: 143 path = av[0]; 144 break; 145 default: 146 Usage(); 147 } 148 } 149 150 /* Get sockets */ 151 if (NgMkSockNode(NULL, &csock, &dsock) < 0) 152 errx(EX_OSERR, "can't get sockets"); 153 154 /* Connect socket node to specified node */ 155 snprintf(ngc.path, sizeof(ngc.path), "%s", path); 156 snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME); 157 snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook); 158 159 if (NgSendMsg(csock, ".", 160 NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0) 161 errx(EX_OSERR, "can't connect to node"); 162 163 if (execFlag) { 164 /* move dsock to fd 0 and 1 */ 165 (void)close(0); 166 (void)close(1); 167 if (!noInput) 168 (void)dup2(dsock, 0); 169 (void)dup2(dsock, 1); 170 171 send_msgs(csock, path); 172 173 /* try executing the program */ 174 (void)execv(av[0], av); 175 err(EX_OSERR, "%s", av[0]); 176 177 } else 178 send_msgs(csock, path); 179 180 /* Close standard input if not reading from it */ 181 if (noInput) 182 fclose(stdin); 183 184 /* Relay data */ 185 while (1) { 186 fd_set rfds; 187 188 /* Setup bits */ 189 FD_ZERO(&rfds); 190 if (!noInput) 191 FD_SET(infd, &rfds); 192 FD_SET(dsock, &rfds); 193 194 /* Wait for something to happen */ 195 if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) 196 err(EX_OSERR, "select"); 197 198 /* Check data from socket */ 199 if (FD_ISSET(dsock, &rfds)) { 200 char buf[BUF_SIZE]; 201 int rl, wl; 202 203 /* Read packet from socket */ 204 if ((rl = NgRecvData(dsock, 205 buf, sizeof(buf), NULL)) < 0) 206 err(EX_OSERR, "read(hook)"); 207 if (rl == 0) 208 errx(EX_OSERR, "read EOF from hook?!"); 209 210 /* Write packet to stdout */ 211 if (asciiFlag) 212 WriteAscii((u_char *) buf, rl); 213 else if ((wl = write(outfd, buf, rl)) != rl) { 214 if (wl < 0) { 215 err(EX_OSERR, "write(stdout)"); 216 } else { 217 errx(EX_OSERR, 218 "stdout: read %d, wrote %d", 219 rl, wl); 220 } 221 } 222 /* Loopback */ 223 if (loopFlag) { 224 if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) 225 err(EX_OSERR, "write(hook)"); 226 } 227 } 228 229 /* Check data from stdin */ 230 if (FD_ISSET(infd, &rfds)) { 231 char buf[BUF_SIZE]; 232 int rl; 233 234 /* Read packet from stdin */ 235 if ((rl = read(infd, buf, sizeof(buf))) < 0) 236 err(EX_OSERR, "read(stdin)"); 237 if (rl == 0) 238 errx(EX_OSERR, "EOF(stdin)"); 239 240 /* Write packet to socket */ 241 if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0) 242 err(EX_OSERR, "write(hook)"); 243 } 244 } 245 } 246 247 /* 248 * Dump data in hex and ASCII form 249 */ 250 static void 251 WriteAscii(u_char *buf, int len) 252 { 253 char ch, sbuf[100]; 254 int k, count; 255 256 for (count = 0; count < len; count += 16) { 257 snprintf(sbuf, sizeof(sbuf), "%04x: ", count); 258 for (k = 0; k < 16; k++) 259 if (count + k < len) 260 snprintf(sbuf + strlen(sbuf), 261 sizeof(sbuf) - strlen(sbuf), 262 "%02x ", buf[count + k]); 263 else 264 snprintf(sbuf + strlen(sbuf), 265 sizeof(sbuf) - strlen(sbuf), " "); 266 snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " "); 267 for (k = 0; k < 16; k++) 268 if (count + k < len) { 269 ch = isprint(buf[count + k]) ? 270 buf[count + k] : '.'; 271 snprintf(sbuf + strlen(sbuf), 272 sizeof(sbuf) - strlen(sbuf), "%c", ch); 273 } else 274 snprintf(sbuf + strlen(sbuf), 275 sizeof(sbuf) - strlen(sbuf), " "); 276 snprintf(sbuf + strlen(sbuf), 277 sizeof(sbuf) - strlen(sbuf), "\n"); 278 (void) write(outfd, sbuf, strlen(sbuf)); 279 } 280 ch = '\n'; 281 write(outfd, &ch, 1); 282 } 283 284 /* 285 * Display usage and exit 286 */ 287 static void 288 Usage(void) 289 { 290 fprintf(stderr, "usage: nghook [-adlnsS] path [hookname]\n"); 291 fprintf(stderr, " or: nghook -e [-n] [-m msg]* path hookname prog " 292 "[args...]\n"); 293 exit(EX_USAGE); 294 } 295 296 /* 297 * Send the messages to the node 298 */ 299 static void 300 send_msgs(int cs, const char *path) 301 { 302 u_int i; 303 304 for (i = 0; i < msgs->sl_cur; i++) 305 if (NgSendAsciiMsg(cs, path, "%s", msgs->sl_str[i]) == -1) 306 err(EX_OSERR, "sending message '%s'", msgs->sl_str[i]); 307 } 308