summaryrefslogtreecommitdiffstats
path: root/sys/net/if_tun.c
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2007-02-04 16:32:46 +0000
committerbms <bms@FreeBSD.org>2007-02-04 16:32:46 +0000
commit77c2e113090f513f7876ee5e02f61ab600b319cf (patch)
tree2b8098cffbe0971d05ca5c30201a51b937a1e7f9 /sys/net/if_tun.c
parent4e9c971afca066f77117383709ba6fa8ee6a6f12 (diff)
downloadFreeBSD-src-77c2e113090f513f7876ee5e02f61ab600b319cf.zip
FreeBSD-src-77c2e113090f513f7876ee5e02f61ab600b319cf.tar.gz
Implement ifnet cloning for tun(4)/tap(4).
Make devfs cloning a sysctl/tunable which defaults to on. If devfs cloning is enabled, only the super-user may create tun(4)/tap(4)/vmnet(4) instances. Devfs cloning is still enabled by default; it may be disabled from the loader or via sysctl with "net.link.tap.devfs_cloning" and "net.link.tun.devfs_cloning". Disabling its use affects potentially all tun(4)/tap(4) consumers including OpenSSH, OpenVPN and VMware. PR: 105228 (potentially also 90413, 105570) Submitted by: Landon Fuller Tested by: Andrej Tobola Approved by: core (rwatson) MFC after: 4 weeks
Diffstat (limited to 'sys/net/if_tun.c')
-rw-r--r--sys/net/if_tun.c84
1 files changed, 77 insertions, 7 deletions
diff --git a/sys/net/if_tun.c b/sys/net/if_tun.c
index b313b18..efd57a2 100644
--- a/sys/net/if_tun.c
+++ b/sys/net/if_tun.c
@@ -45,6 +45,7 @@
#include <sys/random.h>
#include <net/if.h>
+#include <net/if_clone.h>
#include <net/if_types.h>
#include <net/netisr.h>
#include <net/route.h>
@@ -105,13 +106,22 @@ struct tun_softc {
static struct mtx tunmtx;
static MALLOC_DEFINE(M_TUN, TUNNAME, "Tunnel Interface");
static int tundebug = 0;
+static int tundclone = 1;
static struct clonedevs *tunclones;
static TAILQ_HEAD(,tun_softc) tunhead = TAILQ_HEAD_INITIALIZER(tunhead);
SYSCTL_INT(_debug, OID_AUTO, if_tun_debug, CTLFLAG_RW, &tundebug, 0, "");
+SYSCTL_DECL(_net_link);
+SYSCTL_NODE(_net_link, OID_AUTO, tun, CTLFLAG_RW, 0,
+ "IP tunnel software network interface.");
+SYSCTL_INT(_net_link_tun, OID_AUTO, devfs_cloning, CTLFLAG_RW, &tundclone, 0,
+ "Enable legacy devfs interface creation.");
+
+TUNABLE_INT("net.link.tun.devfs_cloning", &tundclone);
+
static void tunclone(void *arg, struct ucred *cred, char *name,
int namelen, struct cdev **dev);
-static void tuncreate(struct cdev *dev);
+static void tuncreate(const char *name, struct cdev *dev);
static int tunifioctl(struct ifnet *, u_long, caddr_t);
static int tuninit(struct ifnet *);
static int tunmodevent(module_t, int, void *);
@@ -119,6 +129,11 @@ static int tunoutput(struct ifnet *, struct mbuf *, struct sockaddr *,
struct rtentry *rt);
static void tunstart(struct ifnet *);
+static int tun_clone_create(struct if_clone *, int, caddr_t);
+static void tun_clone_destroy(struct ifnet *);
+
+IFC_SIMPLE_DECLARE(tun, 0);
+
static d_open_t tunopen;
static d_close_t tunclose;
static d_read_t tunread;
@@ -158,15 +173,45 @@ static struct cdevsw tun_cdevsw = {
.d_name = TUNNAME,
};
+static int
+tun_clone_create(struct if_clone *ifc, int unit, caddr_t params)
+{
+ struct cdev *dev;
+ int i;
+
+ /* find any existing device, or allocate new unit number */
+ i = clone_create(&tunclones, &tun_cdevsw, &unit, &dev, 0);
+ if (i) {
+ /* No preexisting struct cdev *, create one */
+ dev = make_dev(&tun_cdevsw, unit2minor(unit),
+ UID_UUCP, GID_DIALER, 0600, "%s%d", ifc->ifc_name, unit);
+ if (dev != NULL) {
+ dev_ref(dev);
+ dev->si_flags |= SI_CHEAPCLONE;
+ }
+ }
+ tuncreate(ifc->ifc_name, dev);
+
+ return (0);
+}
+
static void
tunclone(void *arg, struct ucred *cred, char *name, int namelen,
struct cdev **dev)
{
- int u, i;
+ char devname[SPECNAMELEN + 1];
+ int u, i, append_unit;
if (*dev != NULL)
return;
+ /*
+ * If tun cloning is enabled, only the superuser can create an
+ * interface.
+ */
+ if (!tundclone || priv_check_cred(cred, PRIV_NET_IFCREATE, 0) != 0)
+ return;
+
if (strcmp(name, TUNNAME) == 0) {
u = -1;
} else if (dev_stdclone(name, NULL, TUNNAME, &u) != 1)
@@ -174,17 +219,29 @@ tunclone(void *arg, struct ucred *cred, char *name, int namelen,
if (u != -1 && u > IF_MAXUNIT)
return; /* Unit number too high */
+ if (u == -1)
+ append_unit = 1;
+ else
+ append_unit = 0;
+
/* find any existing device, or allocate new unit number */
i = clone_create(&tunclones, &tun_cdevsw, &u, dev, 0);
if (i) {
+ if (append_unit) {
+ namelen = snprintf(devname, sizeof(devname), "%s%d", name,
+ u);
+ name = devname;
+ }
/* No preexisting struct cdev *, create one */
*dev = make_dev(&tun_cdevsw, unit2minor(u),
- UID_UUCP, GID_DIALER, 0600, "tun%d", u);
+ UID_UUCP, GID_DIALER, 0600, "%s", name);
if (*dev != NULL) {
dev_ref(*dev);
(*dev)->si_flags |= SI_CHEAPCLONE;
}
}
+
+ if_clone_create(name, namelen, NULL);
}
static void
@@ -206,6 +263,17 @@ tun_destroy(struct tun_softc *tp)
free(tp, M_TUN);
}
+static void
+tun_clone_destroy(struct ifnet *ifp)
+{
+ struct tun_softc *tp = ifp->if_softc;
+
+ mtx_lock(&tunmtx);
+ TAILQ_REMOVE(&tunhead, tp, tun_list);
+ mtx_unlock(&tunmtx);
+ tun_destroy(tp);
+}
+
static int
tunmodevent(module_t mod, int type, void *data)
{
@@ -219,8 +287,10 @@ tunmodevent(module_t mod, int type, void *data)
tag = EVENTHANDLER_REGISTER(dev_clone, tunclone, 0, 1000);
if (tag == NULL)
return (ENOMEM);
+ if_clone_attach(&tun_cloner);
break;
case MOD_UNLOAD:
+ if_clone_detach(&tun_cloner);
EVENTHANDLER_DEREGISTER(dev_clone, tag);
mtx_lock(&tunmtx);
@@ -281,7 +351,7 @@ tunstart(struct ifnet *ifp)
/* XXX: should return an error code so it can fail. */
static void
-tuncreate(struct cdev *dev)
+tuncreate(const char *name, struct cdev *dev)
{
struct tun_softc *sc;
struct ifnet *ifp;
@@ -299,8 +369,8 @@ tuncreate(struct cdev *dev)
ifp = sc->tun_ifp = if_alloc(IFT_PPP);
if (ifp == NULL)
panic("%s%d: failed to if_alloc() interface.\n",
- TUNNAME, dev2unit(dev));
- if_initname(ifp, TUNNAME, dev2unit(dev));
+ name, dev2unit(dev));
+ if_initname(ifp, name, dev2unit(dev));
ifp->if_mtu = TUNMTU;
ifp->if_ioctl = tunifioctl;
ifp->if_output = tunoutput;
@@ -331,7 +401,7 @@ tunopen(struct cdev *dev, int flag, int mode, struct thread *td)
*/
tp = dev->si_drv1;
if (!tp) {
- tuncreate(dev);
+ tuncreate(TUNNAME, dev);
tp = dev->si_drv1;
}
OpenPOWER on IntegriCloud