xref: /freebsd/usr.sbin/nghook/main.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
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 
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 
62 static void	WriteAscii(u_char * buf, int len);
63 static void	Usage(void);
64 
65 static int outfd = STDOUT_FILENO;
66 static int infd = STDIN_FILENO;
67 
68 /*
69  * main()
70  */
71 int
72 main(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  */
207 static void
208 WriteAscii(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  */
244 static void
245 Usage(void)
246 {
247 	fprintf(stderr, "usage: nghook [-adlnsS] path [hookname]\n");
248 	exit(EX_USAGE);
249 }
250