11553Srgrimes/* 21553Srgrimes * main.c 31553Srgrimes * 41553Srgrimes * Copyright (c) 1996-1999 Whistle Communications, Inc. 51553Srgrimes * All rights reserved. 61553Srgrimes * 71553Srgrimes * Subject to the following obligations and disclaimer of warranty, use and 81553Srgrimes * redistribution of this software, in source or object code forms, with or 91553Srgrimes * without modifications are expressly permitted by Whistle Communications; 101553Srgrimes * provided, however, that: 111553Srgrimes * 1. Any and all reproductions of the source or object code must include the 121553Srgrimes * copyright notice above and the following disclaimer of warranties; and 131553Srgrimes * 2. No rights are granted, in any manner or form, to use Whistle 141553Srgrimes * Communications, Inc. trademarks, including the mark "WHISTLE 151553Srgrimes * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 161553Srgrimes * such appears in the above copyright notice or in the software. 171553Srgrimes * 181553Srgrimes * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 191553Srgrimes * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 201553Srgrimes * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 211553Srgrimes * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 221553Srgrimes * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 231553Srgrimes * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 241553Srgrimes * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 251553Srgrimes * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 261553Srgrimes * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 271553Srgrimes * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 281553Srgrimes * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 291553Srgrimes * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 3052098Speter * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 311553Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 321553Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 331553Srgrimes * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 341553Srgrimes * OF SUCH DAMAGE. 351553Srgrimes * 361553Srgrimes * $Whistle: main.c,v 1.9 1999/01/20 00:26:26 archie Exp $ 37110895Sru */ 381553Srgrimes 391553Srgrimes#include <sys/cdefs.h> 401553Srgrimes#include <stdio.h> 41169507Swkoszek#include <stdlib.h> 42169507Swkoszek#include <string.h> 43169507Swkoszek#include <ctype.h> 44169507Swkoszek#include <unistd.h> 45169507Swkoszek#include <sysexits.h> 46169507Swkoszek#include <errno.h> 471553Srgrimes#include <err.h> 48110895Sru#include <stringlist.h> 491553Srgrimes 50134542Speter#include <sys/types.h> 511553Srgrimes#include <sys/socket.h> 5273199Speter#include <sys/select.h> 534571Sgibbs 546803Sgibbs#include <netgraph.h> 5554490Speter 56219819Sjeff#define DEFAULT_HOOKNAME "debug" 571553Srgrimes#define NG_SOCK_HOOK_NAME "hook" 581553Srgrimes 59129073Scognet#define BUF_SIZE (64 * 1024) 60129073Scognet 61129073Scognetstatic void WriteAscii(u_char * buf, int len); 62129073Scognetstatic void Usage(void); 63129073Scognetstatic void send_msgs(int, const char *); 641553Srgrimes 651553Srgrimesstatic int outfd = STDOUT_FILENO; 661553Srgrimesstatic int infd = STDIN_FILENO; 6748525Speter 6848525Speterstatic StringList *msgs; 6948525Speter 7048525Speter/* 7130796Sjoerg * main() 7230796Sjoerg */ 731553Srgrimesint 741553Srgrimesmain(int ac, char *av[]) 751553Srgrimes{ 761553Srgrimes struct ngm_connect ngc; 7773204Speter const char *path = NULL; 7873204Speter const char *hook = DEFAULT_HOOKNAME; 7973204Speter int csock, dsock; 80134542Speter int asciiFlag = 0; 811553Srgrimes int loopFlag = 0; 821553Srgrimes int noInput = 0; 8371879Speter int execFlag = 0; 841553Srgrimes int ch; 851553Srgrimes 86110895Sru if ((msgs = sl_init()) == NULL) 871553Srgrimes err(EX_OSERR, NULL); 881553Srgrimes 891553Srgrimes /* Parse flags */ 901553Srgrimes while ((ch = getopt(ac, av, "aedlm:nsS")) != -1) { 911553Srgrimes switch (ch) { 921553Srgrimes case 'a': 931553Srgrimes asciiFlag = 1; 941553Srgrimes break; 951553Srgrimes case 'd': 9645775Speter NgSetDebug(NgSetDebug(-1) + 1); 9745775Speter break; 98144509Simp case 'e': 99144509Simp execFlag = 1; 1001553Srgrimes break; 1011553Srgrimes case 'l': 102144509Simp loopFlag = 1; 1031553Srgrimes break; 1041553Srgrimes case 'n': 1051553Srgrimes noInput = 1; 1061553Srgrimes break; 1071553Srgrimes case 'm': 1081553Srgrimes if (sl_add(msgs, optarg) == -1) 1091553Srgrimes err(EX_OSERR, NULL); 110110895Sru break; 111110895Sru case 's': 1121553Srgrimes outfd = STDIN_FILENO; 113110895Sru break; 114110895Sru case 'S': 1151553Srgrimes infd = STDOUT_FILENO; 1161553Srgrimes break; 1171553Srgrimes case '?': 1181553Srgrimes default: 1191553Srgrimes Usage(); 1201553Srgrimes } 1211553Srgrimes } 1221553Srgrimes ac -= optind; 12312772Speter av += optind; 124110895Sru 125185186Sthompsa if (execFlag) { 126110895Sru if (asciiFlag || loopFlag) { 1271553Srgrimes fprintf(stderr, "conflicting options\n"); 128169507Swkoszek Usage(); 129110895Sru } 13012772Speter if (ac < 3) 13112772Speter Usage(); 13212772Speter path = av[0]; 133206664Simp hook = av[1]; 134206664Simp av += 2; 135110895Sru ac -= 2; 136110895Sru } else { 13712772Speter /* Get params */ 138110895Sru switch (ac) { 139110895Sru case 2: 140163638Simp hook = av[1]; 141163638Simp /* FALLTHROUGH */ 142163638Simp case 1: 143163638Simp path = av[0]; 144163638Simp break; 145163638Simp default: 146163638Simp Usage(); 147264325Sasomers } 148264325Sasomers } 149264325Sasomers 150264325Sasomers /* Get sockets */ 151264325Sasomers if (NgMkSockNode(NULL, &csock, &dsock) < 0) 152264325Sasomers errx(EX_OSERR, "can't get sockets"); 153264325Sasomers 154169507Swkoszek /* Connect socket node to specified node */ 155169507Swkoszek snprintf(ngc.path, sizeof(ngc.path), "%s", path); 156169507Swkoszek snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME); 157169507Swkoszek snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook); 158169507Swkoszek 159169507Swkoszek if (NgSendMsg(csock, ".", 160169507Swkoszek NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0) 161169507Swkoszek errx(EX_OSERR, "can't connect to node"); 162169507Swkoszek 163169507Swkoszek if (execFlag) { 164169507Swkoszek /* move dsock to fd 0 and 1 */ 165169507Swkoszek (void)close(0); 166169507Swkoszek (void)close(1); 16745744Speter if (!noInput) 16882393Speter (void)dup2(dsock, 0); 169169507Swkoszek (void)dup2(dsock, 1); 17045744Speter 17182393Speter send_msgs(csock, path); 17265091Speter 173169507Swkoszek /* try executing the program */ 17445744Speter (void)execv(av[0], av); 17561640Speter err(EX_OSERR, "%s", av[0]); 17661640Speter 17772684Speter } else 17861640Speter send_msgs(csock, path); 17972684Speter 18061640Speter /* Close standard input if not reading from it */ 18161640Speter if (noInput) 18261640Speter fclose(stdin); 18361640Speter 184153888Sru /* Relay data */ 185153888Sru while (1) { 18661640Speter fd_set rfds; 187169507Swkoszek 188169507Swkoszek /* Setup bits */ 189207260Simp FD_ZERO(&rfds); 1901553Srgrimes if (!noInput) 191169647Simp FD_SET(infd, &rfds); 1921553Srgrimes FD_SET(dsock, &rfds); 19345744Speter 19445744Speter /* Wait for something to happen */ 19579607Sdd if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0) 1961553Srgrimes err(EX_OSERR, "select"); 197110895Sru 1981553Srgrimes /* Check data from socket */ 199129073Scognet if (FD_ISSET(dsock, &rfds)) { 200129073Scognet char buf[BUF_SIZE]; 20145744Speter int rl, wl; 20245744Speter 203151744Sjhb /* Read packet from socket */ 2041553Srgrimes if ((rl = NgRecvData(dsock, 20545744Speter buf, sizeof(buf), NULL)) < 0) 2061553Srgrimes err(EX_OSERR, "read(hook)"); 20733598Seivind if (rl == 0) 20852653Smarcel errx(EX_OSERR, "read EOF from hook?!"); 20933538Seivind 2101553Srgrimes /* Write packet to stdout */ 21152098Speter 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 */ 250static void 251WriteAscii(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 */ 287static void 288Usage(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 */ 299static void 300send_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