main.c revision 119020
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: head/usr.sbin/nghook/main.c 119020 2003-08-17 09:06:08Z charnier $");
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
51#include <sys/types.h>
52#include <sys/socket.h>
53#include <sys/select.h>
54
55#include <netgraph.h>
56
57#define DEFAULT_HOOKNAME	"debug"
58#define NG_SOCK_HOOK_NAME	"hook"
59
60#define BUF_SIZE		(64 * 1024)
61
62static void	WriteAscii(u_char * buf, int len);
63static void	Usage(void);
64
65static int outfd = STDOUT_FILENO;
66static int infd = STDIN_FILENO;
67
68/*
69 * main()
70 */
71int
72main(int ac, char *av[])
73{
74	struct ngm_connect ngc;
75	const char *path = NULL;
76	const char *hook = DEFAULT_HOOKNAME;
77	int     csock, dsock;
78	int     asciiFlag = 0;
79	int     loopFlag = 0;
80	int	noInput = 0;
81	int	ch;
82
83	/* Parse flags */
84	while ((ch = getopt(ac, av, "adlnsS")) != -1) {
85		switch (ch) {
86		case 'a':
87			asciiFlag = 1;
88			break;
89		case 'd':
90			NgSetDebug(NgSetDebug(-1) + 1);
91			break;
92		case 'l':
93			loopFlag = 1;
94			break;
95		case 'n':
96			noInput = 1;
97			break;
98		case 's':
99			outfd = STDIN_FILENO;
100			break;
101		case 'S':
102			infd = STDOUT_FILENO;
103			break;
104		case '?':
105		default:
106			Usage();
107		}
108	}
109	ac -= optind;
110	av += optind;
111
112	/* Get params */
113	switch (ac) {
114	case 2:
115		hook = av[1];
116		/* FALLTHROUGH */
117	case 1:
118		path = av[0];
119		break;
120	default:
121		Usage();
122	}
123
124	/* Get sockets */
125	if (NgMkSockNode(NULL, &csock, &dsock) < 0)
126		errx(EX_OSERR, "can't get sockets");
127
128	/* Connect socket node to specified node */
129	snprintf(ngc.path, sizeof(ngc.path), "%s", path);
130	snprintf(ngc.ourhook, sizeof(ngc.ourhook), NG_SOCK_HOOK_NAME);
131	snprintf(ngc.peerhook, sizeof(ngc.peerhook), "%s", hook);
132
133	if (NgSendMsg(csock, ".",
134	    NGM_GENERIC_COOKIE, NGM_CONNECT, &ngc, sizeof(ngc)) < 0)
135		errx(EX_OSERR, "can't connect to node");
136
137	/* Close standard input if not reading from it */
138	if (noInput)
139		fclose(stdin);
140
141	/* Relay data */
142	while (1) {
143		fd_set  rfds;
144
145		/* Setup bits */
146		FD_ZERO(&rfds);
147		if (!noInput)
148			FD_SET(infd, &rfds);
149		FD_SET(dsock, &rfds);
150
151		/* Wait for something to happen */
152		if (select(FD_SETSIZE, &rfds, NULL, NULL, NULL) < 0)
153			err(EX_OSERR, "select");
154
155		/* Check data from socket */
156		if (FD_ISSET(dsock, &rfds)) {
157			char    buf[BUF_SIZE];
158			int     rl, wl;
159
160			/* Read packet from socket */
161			if ((rl = NgRecvData(dsock,
162			    buf, sizeof(buf), NULL)) < 0)
163				err(EX_OSERR, "read(hook)");
164			if (rl == 0)
165				errx(EX_OSERR, "read EOF from hook?!");
166
167			/* Write packet to stdout */
168			if (asciiFlag)
169				WriteAscii((u_char *) buf, rl);
170			else if ((wl = write(outfd, buf, rl)) != rl) {
171				if (wl < 0) {
172					err(EX_OSERR, "write(stdout)");
173				} else {
174					errx(EX_OSERR,
175					    "stdout: read %d, wrote %d",
176					    rl, wl);
177				}
178			}
179			/* Loopback */
180			if (loopFlag) {
181				if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0)
182					err(EX_OSERR, "write(hook)");
183			}
184		}
185
186		/* Check data from stdin */
187		if (FD_ISSET(infd, &rfds)) {
188			char    buf[BUF_SIZE];
189			int     rl;
190
191			/* Read packet from stdin */
192			if ((rl = read(infd, buf, sizeof(buf))) < 0)
193				err(EX_OSERR, "read(stdin)");
194			if (rl == 0)
195				errx(EX_OSERR, "EOF(stdin)");
196
197			/* Write packet to socket */
198			if (NgSendData(dsock, NG_SOCK_HOOK_NAME, buf, rl) < 0)
199				err(EX_OSERR, "write(hook)");
200		}
201	}
202}
203
204/*
205 * Dump data in hex and ASCII form
206 */
207static void
208WriteAscii(u_char *buf, int len)
209{
210	char    ch, sbuf[100];
211	int     k, count;
212
213	for (count = 0; count < len; count += 16) {
214		snprintf(sbuf, sizeof(sbuf), "%04x:  ", count);
215		for (k = 0; k < 16; k++)
216			if (count + k < len)
217				snprintf(sbuf + strlen(sbuf),
218				    sizeof(sbuf) - strlen(sbuf),
219				    "%02x ", buf[count + k]);
220			else
221				snprintf(sbuf + strlen(sbuf),
222				    sizeof(sbuf) - strlen(sbuf), "   ");
223		snprintf(sbuf + strlen(sbuf), sizeof(sbuf) - strlen(sbuf), " ");
224		for (k = 0; k < 16; k++)
225			if (count + k < len) {
226				ch = isprint(buf[count + k]) ?
227				    buf[count + k] : '.';
228				snprintf(sbuf + strlen(sbuf),
229				    sizeof(sbuf) - strlen(sbuf), "%c", ch);
230			} else
231				snprintf(sbuf + strlen(sbuf),
232				    sizeof(sbuf) - strlen(sbuf), " ");
233		snprintf(sbuf + strlen(sbuf),
234		    sizeof(sbuf) - strlen(sbuf), "\n");
235		(void) write(outfd, sbuf, strlen(sbuf));
236	}
237	ch = '\n';
238	write(outfd, &ch, 1);
239}
240
241/*
242 * Display usage and exit
243 */
244static void
245Usage(void)
246{
247	fprintf(stderr, "usage: nghook [-adlnsS] path [hookname]\n");
248	exit(EX_USAGE);
249}
250