xref: /dragonfly/usr.bin/vknet/vknet.c (revision d50f9ae3)
1cf4f0088SMatthew Dillon /*
2cf4f0088SMatthew Dillon  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
3cf4f0088SMatthew Dillon  *
4cf4f0088SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
5cf4f0088SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
6cf4f0088SMatthew Dillon  *
7cf4f0088SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
8cf4f0088SMatthew Dillon  * modification, are permitted provided that the following conditions
9cf4f0088SMatthew Dillon  * are met:
10cf4f0088SMatthew Dillon  *
11cf4f0088SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
12cf4f0088SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
13cf4f0088SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
14cf4f0088SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
15cf4f0088SMatthew Dillon  *    the documentation and/or other materials provided with the
16cf4f0088SMatthew Dillon  *    distribution.
17cf4f0088SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
18cf4f0088SMatthew Dillon  *    contributors may be used to endorse or promote products derived
19cf4f0088SMatthew Dillon  *    from this software without specific, prior written permission.
20cf4f0088SMatthew Dillon  *
21cf4f0088SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22cf4f0088SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23cf4f0088SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24cf4f0088SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25cf4f0088SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26cf4f0088SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27cf4f0088SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28cf4f0088SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29cf4f0088SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30cf4f0088SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31cf4f0088SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32cf4f0088SMatthew Dillon  * SUCH DAMAGE.
33cf4f0088SMatthew Dillon  */
34cf4f0088SMatthew Dillon /*
35f72c50b3SThomas Nikolajsen  * vknet [-C] [-b local-bridge] [-B remote-bridge] [-r delay[:retries]]
36f72c50b3SThomas Nikolajsen  *       local-spec [user@]remote[:remote-spec]
37f72c50b3SThomas Nikolajsen  * vknet -S [-b local-bridge] local-spec	(server mode)
38cf4f0088SMatthew Dillon  *
39cf4f0088SMatthew Dillon  * Connect a SOCK_SEQPACKET socket or TUN device on the local host with
40cf4f0088SMatthew Dillon  * a SOCK_SEQPACKET socket or TUN device on the remote host through a SSH
41cf4f0088SMatthew Dillon  * connection.  When a TUN device is specified it may be optionally bridged.
42cf4f0088SMatthew Dillon  *
43cf4f0088SMatthew Dillon  * This program expects packetized reads and writes on the local and remote
44cf4f0088SMatthew Dillon  * sides and will re-block them over the SSH stream.
45cf4f0088SMatthew Dillon  */
46cf4f0088SMatthew Dillon 
47cf4f0088SMatthew Dillon #include "vknet.h"
48cf4f0088SMatthew Dillon 
49cf4f0088SMatthew Dillon static void vknet_blastaway(ioinfo_t ios, ioinfo_t iod);
50cf4f0088SMatthew Dillon static void *vknet_stream(void *arg);
51cf4f0088SMatthew Dillon static void vknet_connect(ioinfo_t ios,
52cf4f0088SMatthew Dillon 			  const char *localSide, const char *localBridge);
53be2e52ebSImre Vadasz static pid_t vknet_execssh(int fdin, int fdout, int compressOpt,
54cf4f0088SMatthew Dillon 			   const char *remoteSide, const char *remoteBridge);
55cf4f0088SMatthew Dillon static void usage(void);
56cf4f0088SMatthew Dillon 
57*d50f9ae3SSascha Wildner static pthread_mutex_t MasterLock;
58cf4f0088SMatthew Dillon 
59cf4f0088SMatthew Dillon int
main(int ac,char ** av)60cf4f0088SMatthew Dillon main(int ac, char **av)
61cf4f0088SMatthew Dillon {
62cf4f0088SMatthew Dillon 	int compressOpt = 0;
63cf4f0088SMatthew Dillon 	int remoteOpt = 0;
64cf4f0088SMatthew Dillon 	const char *localBridge = NULL;
65cf4f0088SMatthew Dillon 	const char *remoteBridge = NULL;
66cf4f0088SMatthew Dillon 	const char *localSide;
67cf4f0088SMatthew Dillon 	const char *remoteSide;
68cf4f0088SMatthew Dillon 	char *ptr;
69cf4f0088SMatthew Dillon 	int c;
70cf4f0088SMatthew Dillon 	int retriesOpt = -1;
71cf4f0088SMatthew Dillon 	int timeoutOpt = -1;
72be2e52ebSImre Vadasz 	pid_t sshpid = -1;
73be2e52ebSImre Vadasz 	pid_t p;
74cf4f0088SMatthew Dillon 	struct ioinfo ios;
75cf4f0088SMatthew Dillon 	struct ioinfo iod;
76cf4f0088SMatthew Dillon 
77cf4f0088SMatthew Dillon 	while ((c = getopt(ac, av, "b:B:r:CS")) != -1) {
78cf4f0088SMatthew Dillon 		switch (c) {
79cf4f0088SMatthew Dillon 		case 'b':
80cf4f0088SMatthew Dillon 			localBridge = optarg;
81cf4f0088SMatthew Dillon 			break;
82cf4f0088SMatthew Dillon 		case 'B':
83cf4f0088SMatthew Dillon 			remoteBridge = optarg;
84cf4f0088SMatthew Dillon 			break;
85cf4f0088SMatthew Dillon 		case 'r':
86cf4f0088SMatthew Dillon 			timeoutOpt = strtol(optarg, &ptr, 0);
87cf4f0088SMatthew Dillon 			if (ptr && *ptr == ':')
88cf4f0088SMatthew Dillon 				retriesOpt = strtol(ptr + 1, NULL, 0);
89cf4f0088SMatthew Dillon 			break;
90cf4f0088SMatthew Dillon 		case 'S':
91cf4f0088SMatthew Dillon 			remoteOpt = 1;
92cf4f0088SMatthew Dillon 			break;
93cf4f0088SMatthew Dillon 		case 'C':
94cf4f0088SMatthew Dillon 			compressOpt = 1;
95cf4f0088SMatthew Dillon 			break;
96cf4f0088SMatthew Dillon 		default:
97cf4f0088SMatthew Dillon 			usage();
98cf4f0088SMatthew Dillon 		}
99cf4f0088SMatthew Dillon 	}
100cf4f0088SMatthew Dillon 	av += optind;
101cf4f0088SMatthew Dillon 	ac -= optind;
102cf4f0088SMatthew Dillon 
103cf4f0088SMatthew Dillon 	/*
104cf4f0088SMatthew Dillon 	 * Local and remote arguments.
105cf4f0088SMatthew Dillon 	 */
106cf4f0088SMatthew Dillon 	if (remoteOpt) {
107cf4f0088SMatthew Dillon 		if (ac != 1)
108cf4f0088SMatthew Dillon 			usage();
109cf4f0088SMatthew Dillon 		localSide = av[0];
110cf4f0088SMatthew Dillon 		remoteSide = NULL;
111cf4f0088SMatthew Dillon 	} else {
112cf4f0088SMatthew Dillon 		if (ac != 2)
113cf4f0088SMatthew Dillon 			usage();
114cf4f0088SMatthew Dillon 		localSide = av[0];
115cf4f0088SMatthew Dillon 		remoteSide = av[1];
116cf4f0088SMatthew Dillon 	}
117cf4f0088SMatthew Dillon 
118cf4f0088SMatthew Dillon 	pthread_mutex_init(&MasterLock, NULL);
119cf4f0088SMatthew Dillon 
120cf4f0088SMatthew Dillon retry:
121cf4f0088SMatthew Dillon 	/*
122cf4f0088SMatthew Dillon 	 * Setup connections
123cf4f0088SMatthew Dillon 	 */
124cf4f0088SMatthew Dillon 	vknet_connect(&ios, localSide, localBridge);
125cf4f0088SMatthew Dillon 	if (remoteOpt) {
126cf4f0088SMatthew Dillon 		iod.fdin = 0;
127cf4f0088SMatthew Dillon 		iod.fdout = 1;
128cf4f0088SMatthew Dillon 	} else {
129cf4f0088SMatthew Dillon 		int fds[2];
130cf4f0088SMatthew Dillon 
131cf4f0088SMatthew Dillon 		if (pipe(fds) < 0) {
132cf4f0088SMatthew Dillon 			perror("pipe");
133cf4f0088SMatthew Dillon 			exit(1);
134cf4f0088SMatthew Dillon 		}
135be2e52ebSImre Vadasz 		sshpid = vknet_execssh(fds[1], fds[1], compressOpt,
136cf4f0088SMatthew Dillon 			      remoteSide, remoteBridge);
137cf4f0088SMatthew Dillon 		close(fds[1]);
138cf4f0088SMatthew Dillon 		iod.fdin = fds[0];
139cf4f0088SMatthew Dillon 		iod.fdout = fds[0];
140cf4f0088SMatthew Dillon 	}
141cf4f0088SMatthew Dillon 
142cf4f0088SMatthew Dillon 	/*
143cf4f0088SMatthew Dillon 	 * Blast away, timeout/retry on failure
144cf4f0088SMatthew Dillon 	 */
145cf4f0088SMatthew Dillon 	vknet_blastaway(&ios, &iod);
146cf4f0088SMatthew Dillon 
147cf4f0088SMatthew Dillon 	/*
148be2e52ebSImre Vadasz 	 * Terminate child process
149be2e52ebSImre Vadasz 	 */
150be2e52ebSImre Vadasz 	if (sshpid > 0) {
151be2e52ebSImre Vadasz 		if (kill(sshpid, SIGTERM) != 0)
152be2e52ebSImre Vadasz 			perror("kill");
153be2e52ebSImre Vadasz 		while ((p = waitpid(sshpid, NULL, 0)) != sshpid) {
154be2e52ebSImre Vadasz 			if (p < 0 && errno != EINTR)
155be2e52ebSImre Vadasz 				break;
156be2e52ebSImre Vadasz 		}
157be2e52ebSImre Vadasz 		sshpid = -1;
158be2e52ebSImre Vadasz 	}
159be2e52ebSImre Vadasz 
160be2e52ebSImre Vadasz 	/*
161cf4f0088SMatthew Dillon 	 * Handle timeout/retries
162cf4f0088SMatthew Dillon 	 */
163cf4f0088SMatthew Dillon 	if (timeoutOpt >= 0 && retriesOpt != 0) {
164cf4f0088SMatthew Dillon 		printf("timeout %d retries %d\n", timeoutOpt, retriesOpt);
165cf4f0088SMatthew Dillon 		if (timeoutOpt > 0)
166cf4f0088SMatthew Dillon 			sleep(timeoutOpt);
167cf4f0088SMatthew Dillon 		if (retriesOpt > 0)
168cf4f0088SMatthew Dillon 			--retriesOpt;
169cf4f0088SMatthew Dillon 		goto retry;
170cf4f0088SMatthew Dillon 	}
171cf4f0088SMatthew Dillon 	exit(0);
172cf4f0088SMatthew Dillon }
173cf4f0088SMatthew Dillon 
174cf4f0088SMatthew Dillon static void
vknet_blastaway(ioinfo_t ios,ioinfo_t iod)175cf4f0088SMatthew Dillon vknet_blastaway(ioinfo_t ios, ioinfo_t iod)
176cf4f0088SMatthew Dillon {
177cf4f0088SMatthew Dillon 	struct streaminfo stream1;
178cf4f0088SMatthew Dillon 	struct streaminfo stream2;
179cf4f0088SMatthew Dillon 
180cf4f0088SMatthew Dillon 	pthread_mutex_lock(&MasterLock);
181cf4f0088SMatthew Dillon 	stream1.fdin = ios->fdin;
182cf4f0088SMatthew Dillon 	stream1.fdout = iod->fdout;
183cf4f0088SMatthew Dillon 	stream1.flags = REBLOCK_OUT;
184cf4f0088SMatthew Dillon 	stream1.other = &stream2;
185cf4f0088SMatthew Dillon 	stream2.fdin = iod->fdin;
186cf4f0088SMatthew Dillon 	stream2.fdout = ios->fdout;
187cf4f0088SMatthew Dillon 	stream2.flags = REBLOCK_IN;
188cf4f0088SMatthew Dillon 	stream2.other = &stream1;
189cf4f0088SMatthew Dillon 	pthread_create(&stream1.thread, NULL, vknet_stream, &stream1);
190cf4f0088SMatthew Dillon 	pthread_create(&stream2.thread, NULL, vknet_stream, &stream2);
191cf4f0088SMatthew Dillon 	pthread_mutex_unlock(&MasterLock);
192cf4f0088SMatthew Dillon 	pthread_join(stream1.thread, NULL);
193cf4f0088SMatthew Dillon 	pthread_join(stream2.thread, NULL);
194cf4f0088SMatthew Dillon }
195cf4f0088SMatthew Dillon 
196cf4f0088SMatthew Dillon /*
197cf4f0088SMatthew Dillon  * Transfer packets between two descriptors
198cf4f0088SMatthew Dillon  */
199cf4f0088SMatthew Dillon static
200cf4f0088SMatthew Dillon void *
vknet_stream(void * arg)201cf4f0088SMatthew Dillon vknet_stream(void *arg)
202cf4f0088SMatthew Dillon {
203cf4f0088SMatthew Dillon 	streaminfo_t stream = arg;
204cf4f0088SMatthew Dillon 	struct blkhead head;
205cf4f0088SMatthew Dillon 	u_int8_t *pkt;
206cf4f0088SMatthew Dillon 	int bytes;
207cf4f0088SMatthew Dillon 	int n;
208cf4f0088SMatthew Dillon 	int r;
209cf4f0088SMatthew Dillon 
210cf4f0088SMatthew Dillon 	/*
211cf4f0088SMatthew Dillon 	 * Synchronize with master thread, then loop
212cf4f0088SMatthew Dillon 	 */
213cf4f0088SMatthew Dillon 	pthread_mutex_lock(&MasterLock);
214cf4f0088SMatthew Dillon 	pthread_mutex_unlock(&MasterLock);
215cf4f0088SMatthew Dillon 
216cf4f0088SMatthew Dillon 	pkt = malloc(MAXPKT);
217cf4f0088SMatthew Dillon 
218cf4f0088SMatthew Dillon 	for (;;) {
219cf4f0088SMatthew Dillon 		/*
220cf4f0088SMatthew Dillon 		 * Input side
221cf4f0088SMatthew Dillon 		 */
222cf4f0088SMatthew Dillon 		if (stream->flags & REBLOCK_IN) {
223cf4f0088SMatthew Dillon 			bytes = sizeof(head);
224cf4f0088SMatthew Dillon 			for (n = 0; n < bytes; n += r) {
225cf4f0088SMatthew Dillon 				r = read(stream->fdin, (char *)&head + n,
226cf4f0088SMatthew Dillon 					 bytes - n);
227cf4f0088SMatthew Dillon 				if (r <= 0)
228cf4f0088SMatthew Dillon 					break;
229cf4f0088SMatthew Dillon 			}
230cf4f0088SMatthew Dillon 			if (n != bytes)
231cf4f0088SMatthew Dillon 				break;
232cf4f0088SMatthew Dillon 			if (le32toh(head.magic) != MAGIC)
233cf4f0088SMatthew Dillon 				break;
234cf4f0088SMatthew Dillon 			bytes = le32toh(head.bytes);
235cf4f0088SMatthew Dillon 			if (bytes <= 0 || bytes > MAXPKT)
236cf4f0088SMatthew Dillon 				break;
237cf4f0088SMatthew Dillon 			for (n = 0; n < bytes; n += r) {
238cf4f0088SMatthew Dillon 				r = read(stream->fdin, pkt + n, bytes - n);
239cf4f0088SMatthew Dillon 				if (r <= 0)
240cf4f0088SMatthew Dillon 					break;
241cf4f0088SMatthew Dillon 			}
242cf4f0088SMatthew Dillon 			if (n != bytes)
243cf4f0088SMatthew Dillon 				break;
244cf4f0088SMatthew Dillon 		} else {
245cf4f0088SMatthew Dillon 			bytes = read(stream->fdin, pkt, MAXPKT);
246cf4f0088SMatthew Dillon 			if (bytes <= 0)
247cf4f0088SMatthew Dillon 				break;
248cf4f0088SMatthew Dillon 		}
249cf4f0088SMatthew Dillon 
250cf4f0088SMatthew Dillon 		/*
251cf4f0088SMatthew Dillon 		 * Output side
252cf4f0088SMatthew Dillon 		 */
253cf4f0088SMatthew Dillon 		if (stream->flags & REBLOCK_OUT) {
254cf4f0088SMatthew Dillon 			head.magic = htole32(MAGIC);
255cf4f0088SMatthew Dillon 			head.bytes = htole32(bytes);
256cf4f0088SMatthew Dillon 			if (write(stream->fdout, &head, sizeof(head)) != sizeof(head))
257cf4f0088SMatthew Dillon 				break;
258cf4f0088SMatthew Dillon 			if (write(stream->fdout, pkt, bytes) != bytes)
259cf4f0088SMatthew Dillon 				break;
260cf4f0088SMatthew Dillon 		} else {
261cf4f0088SMatthew Dillon 			if (write(stream->fdout, pkt, bytes) != bytes)
262cf4f0088SMatthew Dillon 				break;
263cf4f0088SMatthew Dillon 		}
264cf4f0088SMatthew Dillon 	}
265cf4f0088SMatthew Dillon 	free(pkt);
266cf4f0088SMatthew Dillon 	close(stream->fdin);
267cf4f0088SMatthew Dillon 	close(stream->fdout);
268cf4f0088SMatthew Dillon 	pthread_cancel(stream->other->thread);
269cf4f0088SMatthew Dillon 	pthread_exit(NULL);
270cf4f0088SMatthew Dillon }
271cf4f0088SMatthew Dillon 
272cf4f0088SMatthew Dillon /*
273f72c50b3SThomas Nikolajsen  * vknet_connect() - Connect to local side, optionally find or bridge the tap
274cf4f0088SMatthew Dillon  *		     interface.
275cf4f0088SMatthew Dillon  */
276cf4f0088SMatthew Dillon static void
vknet_connect(ioinfo_t io,const char * localSide,const char * localBridge)277cf4f0088SMatthew Dillon vknet_connect(ioinfo_t io, const char *localSide, const char *localBridge)
278cf4f0088SMatthew Dillon {
279cf4f0088SMatthew Dillon 	struct ifreq ifr;
280cf4f0088SMatthew Dillon 	struct ifaliasreq ifra;
281cf4f0088SMatthew Dillon 	char *buf = NULL;
282cf4f0088SMatthew Dillon 	int tap_fd;
283cf4f0088SMatthew Dillon 	int tap_unit;
284cf4f0088SMatthew Dillon 	int i;
285cf4f0088SMatthew Dillon 	int s;
286cf4f0088SMatthew Dillon 	int flags;
287cf4f0088SMatthew Dillon 
288cf4f0088SMatthew Dillon 	tap_unit = -1;
289cf4f0088SMatthew Dillon 	tap_fd = -1;
290cf4f0088SMatthew Dillon 
291cf4f0088SMatthew Dillon 	if (strcmp(localSide, "auto") == 0) {
292cf4f0088SMatthew Dillon 		for (i = 0; ; ++i) {
293cf4f0088SMatthew Dillon 			asprintf(&buf, "/dev/tap%d", i);
294cf4f0088SMatthew Dillon 			tap_fd = open(buf, O_RDWR | O_NONBLOCK);
295cf4f0088SMatthew Dillon 			free(buf);
296cf4f0088SMatthew Dillon 			if (tap_fd >= 0 || errno == ENOENT) {
297cf4f0088SMatthew Dillon 				tap_unit = i;
298cf4f0088SMatthew Dillon 				break;
299cf4f0088SMatthew Dillon 			}
300cf4f0088SMatthew Dillon 		}
301cf4f0088SMatthew Dillon 	} else if (strncmp(localSide, "tap", 3) == 0) {
302cf4f0088SMatthew Dillon 		asprintf(&buf, "/dev/%s", localSide);
303cf4f0088SMatthew Dillon 		tap_fd = open(buf, O_RDWR | O_NONBLOCK);
304cf4f0088SMatthew Dillon 		tap_unit = strtol(localSide + 3, NULL, 10);
305cf4f0088SMatthew Dillon 		free(buf);
306cf4f0088SMatthew Dillon 	} else if ((tap_fd = open(localSide, O_RDWR | O_NONBLOCK)) >= 0) {
307cf4f0088SMatthew Dillon 		const char *ptr = localSide + strlen(localSide);
308cf4f0088SMatthew Dillon 		while (ptr > localSide && ptr[-1] >= '0' && ptr[-1] <= '9')
309cf4f0088SMatthew Dillon 			--ptr;
310cf4f0088SMatthew Dillon 		tap_unit = strtol(ptr, NULL, 10);
311cf4f0088SMatthew Dillon 	} else {
312cf4f0088SMatthew Dillon 		struct sockaddr_un sunx;
313cf4f0088SMatthew Dillon 		int len;
314cf4f0088SMatthew Dillon 
315cf4f0088SMatthew Dillon 		snprintf(sunx.sun_path, sizeof(sunx.sun_path), "%s", localSide);
316cf4f0088SMatthew Dillon 		len = offsetof(struct sockaddr_un,
317cf4f0088SMatthew Dillon 			       sun_path[strlen(sunx.sun_path)]);
318cf4f0088SMatthew Dillon 		++len;	/* include nul */
319cf4f0088SMatthew Dillon 		sunx.sun_family = AF_UNIX;
320cf4f0088SMatthew Dillon 		sunx.sun_len = len;
321cf4f0088SMatthew Dillon 
322cf4f0088SMatthew Dillon 		tap_fd = socket(AF_UNIX, SOCK_SEQPACKET, 0);
323cf4f0088SMatthew Dillon 		if (tap_fd >= 0)	 {
324cf4f0088SMatthew Dillon 			if (connect(tap_fd, (void *)&sunx, len) < 0) {
325cf4f0088SMatthew Dillon 				close(tap_fd);
326cf4f0088SMatthew Dillon 				tap_fd = -1;
327cf4f0088SMatthew Dillon 			}
328cf4f0088SMatthew Dillon 		}
329cf4f0088SMatthew Dillon 	}
330cf4f0088SMatthew Dillon 
331cf4f0088SMatthew Dillon 	if (tap_fd < 0) {
332cf4f0088SMatthew Dillon 		err(1, "Unable to connect to %s", localSide);
333cf4f0088SMatthew Dillon 		/* NOT REACHED */
334cf4f0088SMatthew Dillon 	}
335cf4f0088SMatthew Dillon 
336cf4f0088SMatthew Dillon 	fcntl(tap_fd, F_SETFL, 0);
337cf4f0088SMatthew Dillon 	io->fdin = tap_fd;
338cf4f0088SMatthew Dillon 	io->fdout = tap_fd;
339cf4f0088SMatthew Dillon 
340cf4f0088SMatthew Dillon 	/*
341cf4f0088SMatthew Dillon 	 * If this isn't a TAP device we are done.
342cf4f0088SMatthew Dillon 	 */
343cf4f0088SMatthew Dillon 	if (tap_unit < 0)
344cf4f0088SMatthew Dillon 		return;
345cf4f0088SMatthew Dillon 
346cf4f0088SMatthew Dillon 	/*
347cf4f0088SMatthew Dillon 	 * Bring up the TAP interface
348cf4f0088SMatthew Dillon 	 */
349cf4f0088SMatthew Dillon 	bzero(&ifr, sizeof(ifr));
350cf4f0088SMatthew Dillon 	bzero(&ifra, sizeof(ifra));
351cf4f0088SMatthew Dillon 	snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
352cf4f0088SMatthew Dillon 	snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "tap%d", tap_unit);
353cf4f0088SMatthew Dillon 
354cf4f0088SMatthew Dillon 	s = socket(AF_INET, SOCK_DGRAM, 0);
355cf4f0088SMatthew Dillon 
356cf4f0088SMatthew Dillon #if 0
357cf4f0088SMatthew Dillon 	/*
358cf4f0088SMatthew Dillon 	 * Set the interface address if in Secure mode.
359cf4f0088SMatthew Dillon 	 */
360cf4f0088SMatthew Dillon 	if (SecureOpt) {
361cf4f0088SMatthew Dillon 		struct sockaddr_in *in;
362cf4f0088SMatthew Dillon 
363cf4f0088SMatthew Dillon 		in = (void *)&ifra.ifra_addr;
364cf4f0088SMatthew Dillon 		in->sin_family = AF_INET;
365cf4f0088SMatthew Dillon 		in->sin_len = sizeof(ifra.ifra_addr);
366cf4f0088SMatthew Dillon 		in->sin_addr = NetAddress;
367cf4f0088SMatthew Dillon 		in = (void *)&ifra.ifra_mask;
368cf4f0088SMatthew Dillon 		in->sin_family = AF_INET;
369cf4f0088SMatthew Dillon 		in->sin_len = sizeof(ifra.ifra_mask);
370cf4f0088SMatthew Dillon 		in->sin_addr = NetMask;
371cf4f0088SMatthew Dillon 		if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
372cf4f0088SMatthew Dillon 			perror("Unable to set address on tap interface");
373cf4f0088SMatthew Dillon 			exit(1);
374cf4f0088SMatthew Dillon 		}
375cf4f0088SMatthew Dillon 	}
376cf4f0088SMatthew Dillon #endif
377cf4f0088SMatthew Dillon 
378cf4f0088SMatthew Dillon 	/*
379cf4f0088SMatthew Dillon 	 * Turn up the interface
380cf4f0088SMatthew Dillon 	 */
381cf4f0088SMatthew Dillon 	flags = IFF_UP;
382cf4f0088SMatthew Dillon 	if (ioctl(s, SIOCGIFFLAGS, &ifr) >= 0) {
383cf4f0088SMatthew Dillon 		bzero(&ifr, sizeof(ifr));
384cf4f0088SMatthew Dillon 		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
385cf4f0088SMatthew Dillon 		ifr.ifr_flags |= flags & 0xFFFF;
386cf4f0088SMatthew Dillon 		ifr.ifr_flagshigh |= flags >> 16;
387cf4f0088SMatthew Dillon 		if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
388cf4f0088SMatthew Dillon 			perror("Unable to set IFF_UP on tap interface");
389cf4f0088SMatthew Dillon 			exit(1);
390cf4f0088SMatthew Dillon 		}
391cf4f0088SMatthew Dillon 	}
392cf4f0088SMatthew Dillon 
393cf4f0088SMatthew Dillon 	/*
394cf4f0088SMatthew Dillon 	 * If a bridge was specified associate the tap interface with the
395cf4f0088SMatthew Dillon 	 * bridge.
396cf4f0088SMatthew Dillon 	 */
397cf4f0088SMatthew Dillon 	if (localBridge) {
398cf4f0088SMatthew Dillon 		struct ifbreq ifbr;
399cf4f0088SMatthew Dillon 		struct ifdrv ifd;
400cf4f0088SMatthew Dillon 
401cf4f0088SMatthew Dillon 		/*
402cf4f0088SMatthew Dillon 		 * Create the bridge if necessary.
403cf4f0088SMatthew Dillon 		 */
404cf4f0088SMatthew Dillon 		bzero(&ifr, sizeof(ifr));
405cf4f0088SMatthew Dillon 		snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", localBridge);
406cf4f0088SMatthew Dillon 		if (ioctl(s, SIOCIFCREATE, &ifr) < 0) {
407cf4f0088SMatthew Dillon 			if (errno != EEXIST) {
408cf4f0088SMatthew Dillon 				perror("Unable to create bridge interface");
409cf4f0088SMatthew Dillon 				exit(1);
410cf4f0088SMatthew Dillon 			}
411cf4f0088SMatthew Dillon 		}
412cf4f0088SMatthew Dillon 
413cf4f0088SMatthew Dillon 
414cf4f0088SMatthew Dillon 		/*
415cf4f0088SMatthew Dillon 		 * Add the tap interface to the bridge
416cf4f0088SMatthew Dillon 		 */
417cf4f0088SMatthew Dillon 		bzero(&ifbr, sizeof(ifbr));
418cf4f0088SMatthew Dillon 		snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
419cf4f0088SMatthew Dillon 			 "tap%d", tap_unit);
420cf4f0088SMatthew Dillon 
421cf4f0088SMatthew Dillon 		bzero(&ifd, sizeof(ifd));
422cf4f0088SMatthew Dillon 		snprintf(ifd.ifd_name, sizeof(ifd.ifd_name), "%s", localBridge);
423cf4f0088SMatthew Dillon 		ifd.ifd_cmd = BRDGADD;
424cf4f0088SMatthew Dillon 		ifd.ifd_len = sizeof(ifbr);
425cf4f0088SMatthew Dillon 		ifd.ifd_data = &ifbr;
426cf4f0088SMatthew Dillon 
427cf4f0088SMatthew Dillon 		if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
428cf4f0088SMatthew Dillon 			if (errno != EEXIST) {
429cf4f0088SMatthew Dillon 				perror("Unable to add tap ifc to bridge!");
430cf4f0088SMatthew Dillon 				exit(1);
431cf4f0088SMatthew Dillon 			}
432cf4f0088SMatthew Dillon 		}
433cf4f0088SMatthew Dillon 	}
434cf4f0088SMatthew Dillon 	close(s);
435cf4f0088SMatthew Dillon }
436cf4f0088SMatthew Dillon 
437cf4f0088SMatthew Dillon /*
438cf4f0088SMatthew Dillon  * Connect to the remote machine with ssh and set up a stream
439cf4f0088SMatthew Dillon  */
440be2e52ebSImre Vadasz static pid_t
vknet_execssh(int fdin,int fdout,int compressOpt,const char * remoteSide,const char * remoteBridge)441cf4f0088SMatthew Dillon vknet_execssh(int fdin, int fdout, int compressOpt,
442cf4f0088SMatthew Dillon 	      const char *remoteSide, const char *remoteBridge)
443cf4f0088SMatthew Dillon {
444cf4f0088SMatthew Dillon 	char *remoteHost;
445cf4f0088SMatthew Dillon 	char *remotePath;
446cf4f0088SMatthew Dillon 	const char *av[24];
447cf4f0088SMatthew Dillon 	int ac;
448cf4f0088SMatthew Dillon 	pid_t pid;
449cf4f0088SMatthew Dillon 
450cf4f0088SMatthew Dillon 	/*
451cf4f0088SMatthew Dillon 	 * Fork / parent returns.
452cf4f0088SMatthew Dillon 	 */
453cf4f0088SMatthew Dillon 	if ((pid = fork()) > 0)
454be2e52ebSImre Vadasz 		return pid;
455cf4f0088SMatthew Dillon 	if (pid < 0) {
456cf4f0088SMatthew Dillon 		perror("fork");
457cf4f0088SMatthew Dillon 		exit(1);
458cf4f0088SMatthew Dillon 	}
459cf4f0088SMatthew Dillon 
460cf4f0088SMatthew Dillon 	/*
461cf4f0088SMatthew Dillon 	 * Setup stdin, stdout
462cf4f0088SMatthew Dillon 	 */
463cf4f0088SMatthew Dillon 	assert(fdin > 2);
464cf4f0088SMatthew Dillon 	assert(fdout > 2);
465cf4f0088SMatthew Dillon 	dup2(fdin, 0);
466cf4f0088SMatthew Dillon 	dup2(fdout, 1);
467cf4f0088SMatthew Dillon 	close(fdin);
468cf4f0088SMatthew Dillon 	close(fdout);
469cf4f0088SMatthew Dillon 
470cf4f0088SMatthew Dillon 	/*
471cf4f0088SMatthew Dillon 	 * Set up arguments
472cf4f0088SMatthew Dillon 	 */
473cf4f0088SMatthew Dillon 	remoteHost = strdup(remoteSide);
474cf4f0088SMatthew Dillon 	if ((remotePath = strchr(remoteHost, ':')) != NULL) {
475cf4f0088SMatthew Dillon 		*remotePath++ = 0;
476cf4f0088SMatthew Dillon 	} else {
477f72c50b3SThomas Nikolajsen 		remotePath = strdup("/var/run/vknet");
478cf4f0088SMatthew Dillon 	}
479cf4f0088SMatthew Dillon 	ac = 0;
480cf4f0088SMatthew Dillon 	av[ac++] = "ssh";
481cf4f0088SMatthew Dillon 	if (compressOpt)
482cf4f0088SMatthew Dillon 		av[ac++] = "-C";
483cf4f0088SMatthew Dillon 	av[ac++] = "-x";
484cf4f0088SMatthew Dillon 	av[ac++] = "-T";
485cf4f0088SMatthew Dillon 	av[ac++] = "-e";
486cf4f0088SMatthew Dillon 	av[ac++] = "none";
487cf4f0088SMatthew Dillon 	av[ac++] = remoteHost;
488cf4f0088SMatthew Dillon 	av[ac++] = "exec";
489cf4f0088SMatthew Dillon 	av[ac++] = "vknet";
490cf4f0088SMatthew Dillon 	av[ac++] = "-S";
491cf4f0088SMatthew Dillon 	if (remoteBridge) {
492cf4f0088SMatthew Dillon 		av[ac++] = "-b";
493cf4f0088SMatthew Dillon 		av[ac++] = remoteBridge;
494cf4f0088SMatthew Dillon 	}
495cf4f0088SMatthew Dillon 	av[ac++] = remotePath;
496cf4f0088SMatthew Dillon 	av[ac++] = NULL;
497cf4f0088SMatthew Dillon 	execv("/usr/bin/ssh", (void *)av);
498be2e52ebSImre Vadasz 	exit(1);
499cf4f0088SMatthew Dillon }
500cf4f0088SMatthew Dillon 
501cf4f0088SMatthew Dillon /*
502cf4f0088SMatthew Dillon  * Misc
503cf4f0088SMatthew Dillon  */
504cf4f0088SMatthew Dillon static
505cf4f0088SMatthew Dillon void
usage(void)506cf4f0088SMatthew Dillon usage(void)
507cf4f0088SMatthew Dillon {
508cf4f0088SMatthew Dillon 	fprintf(stderr,
509f72c50b3SThomas Nikolajsen 		"vknet [-C] [-b local-bridge] [-B remote-bridge] [-r delay[:retries]]\n"
510f72c50b3SThomas Nikolajsen 		"      local-spec [user@]remote[:remote-spec]\n"
511f72c50b3SThomas Nikolajsen 		"vknet -S [-b local-bridge] local-spec\n"
512cf4f0088SMatthew Dillon 	);
513cf4f0088SMatthew Dillon 	exit(1);
514cf4f0088SMatthew Dillon }
515cf4f0088SMatthew Dillon 
516