2 * Copyright (c) 2008 The DragonFly Project. All rights reserved.
4 * This code is derived from software contributed to The DragonFly Project
5 * by Matthew Dillon <dillon@backplane.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * 3. Neither the name of The DragonFly Project nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific, prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * vknet [-cdU] [-b bridgeN] [-p socket_path] [-t tapN] [address/cidrbits]
37 * Create a named unix-domain socket which userland vkernels can open
38 * to gain access to a local network. All connections to the socket
39 * are bridged together and the local network can also be bridged onto
40 * a TAP interface by specifying the -t option.
44 static ioinfo_t
vknet_tap(const char *tapName
, const char *bridgeName
);
45 static int vknet_listener(const char *pathName
);
46 static void vknet_acceptor(int net_fd
);
47 static void *vknet_io(void *arg
);
48 static int vknet_connect(const char *pathName
);
49 static void vknet_monitor(int net_fd
);
50 static void usage(void);
51 static void writepid(void);
52 static void cleanup(int);
54 pthread_mutex_t BridgeMutex
;
59 const char *pidfile
= "/var/run/vknetd.pid";
61 struct in_addr NetAddress
;
62 struct in_addr NetMask
;
65 main(int ac
, char **av
)
67 const char *pathName
= "/var/run/vknet";
68 const char *tapName
= "auto";
69 const char *bridgeName
= NULL
;
76 while ((c
= getopt(ac
, av
, "b:cdp:i:t:U")) != -1) {
109 * Special connect/debug mode
112 net_fd
= vknet_connect(pathName
);
117 vknet_monitor(net_fd
);
122 * In secure mode (the default), a network address/mask must be
123 * specified. e.g. 10.1.0.0/16. Any traffic going out the TAP
124 * interface will be filtered.
126 * If non-secure mode the network address/mask is optional.
128 if (SecureOpt
|| SetAddrOpt
) {
133 if (ac
== 0 || strchr(av
[0], '/') == NULL
)
136 if (inet_pton(AF_INET
, strtok(str
, "/"), &NetAddress
) <= 0)
138 masklen
= strtoul(strtok(NULL
, "/"), NULL
, 10);
139 mask
= (1 << (32 - masklen
)) - 1;
140 NetMask
.s_addr
= htonl(~mask
);
144 * Normal operation, create the tap/bridge and listener. This
145 * part is not threaded.
149 if ((tap_info
= vknet_tap(tapName
, bridgeName
)) == NULL
) {
153 if ((net_fd
= vknet_listener(pathName
)) < 0) {
154 perror("listener: ");
159 * Now make us a demon and start the threads going.
166 signal(SIGINT
, cleanup
);
167 signal(SIGHUP
, cleanup
);
168 signal(SIGTERM
, cleanup
);
170 pthread_mutex_init(&BridgeMutex
, NULL
);
171 pthread_create(&dummy_td
, NULL
, vknet_io
, tap_info
);
172 vknet_acceptor(net_fd
);
177 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
180 vknet_tap(const char *tapName
, const char *bridgeName
)
183 struct ifaliasreq ifra
;
193 if (strcmp(tapName
, "auto") == 0) {
195 asprintf(&buf
, "/dev/tap%d", i
);
196 tap_fd
= open(buf
, O_RDWR
| O_NONBLOCK
);
198 if (tap_fd
>= 0 || errno
== ENOENT
)
201 } else if (strncmp(tapName
, "tap", 3) == 0) {
202 asprintf(&buf
, "/dev/%s", tapName
);
203 tap_fd
= open(buf
, O_RDWR
| O_NONBLOCK
);
206 tap_fd
= open(tapName
, O_RDWR
| O_NONBLOCK
);
212 * Figure out the tap unit number
214 if (fstat(tap_fd
, &st
) < 0) {
218 tap_unit
= TAPDEV_MINOR(st
.st_rdev
);
223 fcntl(tap_fd
, F_SETFL
, 0);
224 bzero(&ifr
, sizeof(ifr
));
225 bzero(&ifra
, sizeof(ifra
));
226 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "tap%d", tap_unit
);
227 snprintf(ifra
.ifra_name
, sizeof(ifra
.ifra_name
), "tap%d", tap_unit
);
229 s
= socket(AF_INET
, SOCK_DGRAM
, 0);
232 * Set the interface address if in Secure mode.
235 struct sockaddr_in
*in
;
237 in
= (void *)&ifra
.ifra_addr
;
238 in
->sin_family
= AF_INET
;
239 in
->sin_len
= sizeof(ifra
.ifra_addr
);
240 in
->sin_addr
= NetAddress
;
241 in
= (void *)&ifra
.ifra_mask
;
242 in
->sin_family
= AF_INET
;
243 in
->sin_len
= sizeof(ifra
.ifra_mask
);
244 in
->sin_addr
= NetMask
;
245 if (ioctl(s
, SIOCAIFADDR
, &ifra
) < 0) {
246 perror("Unable to set address on tap interface");
252 * Turn up the interface
255 if (ioctl(s
, SIOCGIFFLAGS
, &ifr
) >= 0) {
256 bzero(&ifr
, sizeof(ifr
));
257 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "tap%d", tap_unit
);
258 ifr
.ifr_flags
|= flags
& 0xFFFF;
259 ifr
.ifr_flagshigh
|= flags
>> 16;
260 if (ioctl(s
, SIOCSIFFLAGS
, &ifr
) < 0) {
261 perror("Unable to set IFF_UP on tap interface");
271 * Create the bridge if necessary.
273 bzero(&ifr
, sizeof(ifr
));
274 snprintf(ifr
.ifr_name
, sizeof(ifr
.ifr_name
), "%s", bridgeName
);
275 if (ioctl(s
, SIOCIFCREATE
, &ifr
) < 0) {
276 if (errno
!= EEXIST
) {
277 perror("Unable to create bridge interface");
284 * Add the tap interface to the bridge
286 bzero(&ifbr
, sizeof(ifbr
));
287 snprintf(ifbr
.ifbr_ifsname
, sizeof(ifbr
.ifbr_ifsname
),
290 bzero(&ifd
, sizeof(ifd
));
291 snprintf(ifd
.ifd_name
, sizeof(ifd
.ifd_name
), "%s", bridgeName
);
292 ifd
.ifd_cmd
= BRDGADD
;
293 ifd
.ifd_len
= sizeof(ifbr
);
294 ifd
.ifd_data
= &ifbr
;
296 if (ioctl(s
, SIOCSDRVSPEC
, &ifd
) < 0) {
297 if (errno
!= EEXIST
) {
298 perror("Unable to add tap ifc to bridge!");
305 info
= malloc(sizeof(*info
));
306 bzero(info
, sizeof(*info
));
315 vknet_listener(const char *pathName
)
317 struct sockaddr_un sunx
;
324 * Group access to our named unix domain socket.
326 if ((grp
= getgrnam("vknet")) == NULL
) {
327 fprintf(stderr
, "The 'vknet' group must exist\n");
336 snprintf(sunx
.sun_path
, sizeof(sunx
.sun_path
), "%s", pathName
);
337 len
= offsetof(struct sockaddr_un
, sun_path
[strlen(sunx
.sun_path
)]);
338 ++len
; /* include nul */
339 sunx
.sun_family
= AF_UNIX
;
342 net_fd
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
346 if (bind(net_fd
, (void *)&sunx
, len
) < 0) {
350 if (listen(net_fd
, 1024) < 0) {
354 if (chown(pathName
, (uid_t
)-1, gid
) < 0) {
358 if (chmod(pathName
, 0660) < 0) {
367 vknet_acceptor(int net_fd
)
369 struct sockaddr_un sunx
;
376 sunx_len
= sizeof(sunx
);
377 rfd
= accept(net_fd
, (void *)&sunx
, &sunx_len
);
380 info
= malloc(sizeof(*info
));
381 bzero(info
, sizeof(*info
));
384 pthread_create(&dummy_td
, NULL
, vknet_io
, info
);
389 * This I/O thread implements the core of the bridging code.
400 pthread_detach(pthread_self());
403 * Assign as a bridge slot using our thread id.
405 pthread_mutex_lock(&BridgeMutex
);
406 bridge
= bridge_add(info
);
407 pthread_mutex_unlock(&BridgeMutex
);
410 * Read packet loop. Writing is handled by the bridge code.
412 pkt
= malloc(MAXPKT
);
413 while ((bytes
= read(info
->fd
, pkt
, MAXPKT
)) > 0) {
414 pthread_mutex_lock(&BridgeMutex
);
415 bridge_packet(bridge
, pkt
, bytes
);
416 pthread_mutex_unlock(&BridgeMutex
);
422 pthread_mutex_lock(&BridgeMutex
);
424 pthread_mutex_unlock(&BridgeMutex
);
435 vknet_connect(const char *pathName
)
437 struct sockaddr_un sunx
;
441 snprintf(sunx
.sun_path
, sizeof(sunx
.sun_path
), "%s", pathName
);
442 len
= offsetof(struct sockaddr_un
, sun_path
[strlen(sunx
.sun_path
)]);
443 ++len
; /* include nul */
444 sunx
.sun_family
= AF_UNIX
;
447 net_fd
= socket(AF_UNIX
, SOCK_SEQPACKET
, 0);
450 if (connect(net_fd
, (void *)&sunx
, len
) < 0) {
458 vknet_monitor(int net_fd
)
464 pkt
= malloc(MAXPKT
);
465 while ((bytes
= read(net_fd
, pkt
, MAXPKT
)) > 0) {
466 printf("%02x:%02x:%02x:%02x:%02x:%02x <- "
467 "%02x:%02x:%02x:%02x:%02x:%02x",
468 pkt
[0], pkt
[1], pkt
[2], pkt
[3], pkt
[4], pkt
[5],
469 pkt
[6], pkt
[7], pkt
[8], pkt
[9], pkt
[10], pkt
[11]);
470 for (i
= 12; i
< bytes
; ++i
) {
471 if (((i
- 12) & 15) == 0) {
474 printf(" %02x", pkt
[i
]);
489 if ((pf
= fopen(pidfile
, "w+")) == NULL
)
490 errx(1, "Failed to create pidfile %s", pidfile
);
492 if ((fprintf(pf
, "%d\n", getpid())) < 1)
499 cleanup(int __unused sig
)
509 fprintf(stderr
, "usage: vknet [-cdU] [-b bridgeN] [-p socket_path] [-i pidfile] [-t tapN] [address/cidrbits]\n");
510 fprintf(stderr
, "address/cidrbits must be specified in default secure mode.\n");