Re: vmd: add support for local inet6 interfaces
On Tue, Nov 20, 2018 at 03:24:18PM +0100, Reyk Floeter wrote: > Hi > > On Fri, Nov 16, 2018 at 05:35:03PM +0100, Reyk Floeter wrote: > > "local interface" (-L) is an amazing feature and I use it every day; > > but it is IPv4-only and now I realized that I need IPv6 too. > > > > The attached diff implements IPv6 support for local interfaces. > > > > Updated diff with feedback from kn@ and ccardenas@ (thanks, Carlos, > for testing!) with the following changes: > > - keep the auto-generated local inet6 prefix across reloads. > - clarify the manpage describing the fd00::/8 prefix > - comments and minor things > > OK? > > Reyk > I'm good with the updated diff. ok ccardenas@ +--+ Carlos
Re: vmd: add support for local inet6 interfaces
Hi On Fri, Nov 16, 2018 at 05:35:03PM +0100, Reyk Floeter wrote: > "local interface" (-L) is an amazing feature and I use it every day; > but it is IPv4-only and now I realized that I need IPv6 too. > > The attached diff implements IPv6 support for local interfaces. > Updated diff with feedback from kn@ and ccardenas@ (thanks, Carlos, for testing!) with the following changes: - keep the auto-generated local inet6 prefix across reloads. - clarify the manpage describing the fd00::/8 prefix - comments and minor things OK? Reyk Index: usr.sbin/vmd/config.c === RCS file: /cvs/src/usr.sbin/vmd/config.c,v retrieving revision 1.54 diff -u -p -u -p -r1.54 config.c --- usr.sbin/vmd/config.c 26 Oct 2018 11:24:45 - 1.54 +++ usr.sbin/vmd/config.c 20 Nov 2018 14:22:49 - @@ -42,17 +42,44 @@ /* Supported bridge types */ const char *vmd_descsw[] = { "switch", "bridge", NULL }; +static int config_init_localprefix(struct vmd_config *); + +static int +config_init_localprefix(struct vmd_config *cfg) +{ + struct sockaddr_in6 *sin6; + + if (host(VMD_DHCP_PREFIX, &cfg->cfg_localprefix) == -1) + return (-1); + + /* IPv6 is disabled by default */ + cfg->cfg_flags &= ~VMD_CFG_INET6; + + /* Generate random IPv6 prefix only once */ + if (cfg->cfg_flags & VMD_CFG_AUTOINET6) + return (0); + if (host(VMD_ULA_PREFIX, &cfg->cfg_localprefix6) == -1) + return (-1); + /* Randomize the 56 bits "Global ID" and "Subnet ID" */ + sin6 = ss2sin6(&cfg->cfg_localprefix6.ss); + arc4random_buf(&sin6->sin6_addr.s6_addr[1], 7); + cfg->cfg_flags |= VMD_CFG_AUTOINET6; + + return (0); +} + int config_init(struct vmd *env) { - struct privsep *ps = &env->vmd_ps; - unsigned int what; + struct privsep *ps = &env->vmd_ps; + unsigned int what; /* Global configuration */ ps->ps_what[PROC_PARENT] = CONFIG_ALL; ps->ps_what[PROC_VMM] = CONFIG_VMS; - if (host(VMD_DHCP_PREFIX, &env->vmd_cfg.cfg_localprefix) == -1) + /* Local prefix */ + if (config_init_localprefix(&env->vmd_cfg) == -1) return (-1); /* Other configuration */ @@ -90,7 +117,7 @@ config_purge(struct vmd *env, unsigned i __func__, ps->ps_title[privsep_process]); /* Reset global configuration (prefix was verified before) */ - (void)host(VMD_DHCP_PREFIX, &env->vmd_cfg.cfg_localprefix); + config_init_localprefix(&env->vmd_cfg); /* Reset other configuration */ what = ps->ps_what[privsep_process] & reset; Index: usr.sbin/vmd/dhcp.c === RCS file: /cvs/src/usr.sbin/vmd/dhcp.c,v retrieving revision 1.5 diff -u -p -u -p -r1.5 dhcp.c --- usr.sbin/vmd/dhcp.c 17 Aug 2018 07:12:28 - 1.5 +++ usr.sbin/vmd/dhcp.c 20 Nov 2018 14:22:49 - @@ -109,7 +109,7 @@ dhcp_request(struct vionet_dev *dev, cha resp.xid = req.xid; if ((client_addr.s_addr = - vm_priv_addr(&env->vmd_cfg.cfg_localprefix, + vm_priv_addr(&env->vmd_cfg, dev->vm_vmid, dev->idx, 1)) == 0) return (-1); memcpy(&resp.yiaddr, &client_addr, @@ -119,7 +119,7 @@ dhcp_request(struct vionet_dev *dev, cha ss2sin(&pc.pc_dst)->sin_port = htons(CLIENT_PORT); if ((server_addr.s_addr = - vm_priv_addr(&env->vmd_cfg.cfg_localprefix, + vm_priv_addr(&env->vmd_cfg, dev->vm_vmid, dev->idx, 0)) == 0) return (-1); memcpy(&resp.siaddr, &server_addr, Index: usr.sbin/vmd/parse.y === RCS file: /cvs/src/usr.sbin/vmd/parse.y,v retrieving revision 1.48 diff -u -p -u -p -r1.48 parse.y --- usr.sbin/vmd/parse.y1 Nov 2018 00:18:44 - 1.48 +++ usr.sbin/vmd/parse.y20 Nov 2018 14:22:49 - @@ -120,9 +120,9 @@ typedef struct { %token INCLUDE ERROR -%token ADD ALLOW BOOT CDROM DISABLE DISK DOWN ENABLE FORMAT GROUP INSTANCE -%token INTERFACE LLADDR LOCAL LOCKED MEMORY NIFS OWNER PATH PREFIX RDOMAIN -%token SIZE SOCKET SWITCH UP VM VMID +%token ADD ALLOW BOOT CDROM DISABLE DISK DOWN ENABLE FORMAT GROUP INET6 +%token INSTANCE INTERFACE LLADDR LOCAL LOCKED MEMORY NIFS OWNER PATH PREFIX +%token RDOMAIN SIZE SOCKET SWITCH UP VM VMID %token NUMBER %token STRING %typelladdr @@ -181,10 +181,27 @@ varset: STRING '=' STRING { } ; -main : LOCAL PREFIX STRING { +main : LOCAL INET6 { + env->vmd_cfg.cfg_flags |= VMD_CFG_INET6; + } + | LOCAL INET6 PREFIX STRING { + struct address h; + + if (host($4, &h) == -1 || +
Re: vmd: add support for local inet6 interfaces
On Fri, Nov 16, 2018 at 05:35:03PM +0100, Reyk Floeter wrote: > Hi, > > "local interface" (-L) is an amazing feature and I use it every day; > but it is IPv4-only and now I realized that I need IPv6 too. > > The attached diff implements IPv6 support for local interfaces. > > A few notes and limitations: > > - Unlike the embedded IPv4 DHCP server, it does not implement a > DHCPv6/rtsol responder in vmd. It relies on a rad(8) change that I've > sent earlier today. Configuring rad is easy enough and IPv6 users are > used to jumping though extra hoops: use my rad diff and run the daemon > with "interface tap" in /etc/rad.conf. > > - It is disabled by default. You can enable it with a global option > "local inet6" (to get a runtime random fd00::/8 ULA prefix) or "local > inet6 prefix xxx::/64" (to configure your own prefix). For > simplicity, the prefix is a global and not a per-VM option. > > - Once enabled, IPv6 will be enabled and an additional IPv6 address > configured on the host's VM tap(4) interface whenever you create it > with "local interface" / -L. > > - The IPv6 address is derived from the configured prefix and the IPv4 > address of the local interface on the VM side. This way it embeds the > VM and interface Id and you can even pf af-to it to IPv4 again! > > ``` > vm_priv_ifconfig: interface tap0 address 100.64.9.2/31 > vm_priv_ifconfig: interface tap0 address fdfc:6be5:806:930a:6440:903:0:1/96 > > 100.64.9.3 > ``` > > - The resulting address is suitable for rad(8) - just run "ifconfig > vio0 inet6 autoconf" in the guest and you'll get your /96 IPv6 > address. > > ``` > vio0: > flags=208b43 > mtu 1500 > lladdr fe:e1:bb:d1:88:4f > index 1 priority 0 llprio 3 > groups: egress > media: Ethernet autoselect > status: active > inet 100.64.9.3 netmask 0xfffe > inet6 fe80::7a1f:6128:505d:4ea5%vio0 prefixlen 64 scopeid 0x1 > inet6 fdfc:6be5:806:930a:6440:903:b11c:516 prefixlen 96 autoconf > autoconfprivacy pltime 86063 vltime 604794 > inet6 fdfc:6be5:806:930a:6440:903:d457:347a prefixlen 96 autoconf > pltime 604794 vltime 2591994 > ``` > > - The only problem is that the IPv6 address is nondeterministic where > you cannot guess the VM's IPv6 address "from the outside" (32 bits of > entropy for the guest IP). It tried it with a /127 prefix but > slaacd/rad don't handle this very well as it has a 50% chance of > creating a duplicate with the host's IP. I didn't attempt to "fix" it > as it would probably be incompatible with other rtsol clients. So I > eventually decided that this is not important as I would still use the > IPv4 address to log in - the IPv6 address is primarily used for > outbound connections. > > OK? > > Reyk Niceok ccardenas@ +--+ Carlos
vmd: add support for local inet6 interfaces
Hi, "local interface" (-L) is an amazing feature and I use it every day; but it is IPv4-only and now I realized that I need IPv6 too. The attached diff implements IPv6 support for local interfaces. A few notes and limitations: - Unlike the embedded IPv4 DHCP server, it does not implement a DHCPv6/rtsol responder in vmd. It relies on a rad(8) change that I've sent earlier today. Configuring rad is easy enough and IPv6 users are used to jumping though extra hoops: use my rad diff and run the daemon with "interface tap" in /etc/rad.conf. - It is disabled by default. You can enable it with a global option "local inet6" (to get a runtime random fd00::/8 ULA prefix) or "local inet6 prefix xxx::/64" (to configure your own prefix). For simplicity, the prefix is a global and not a per-VM option. - Once enabled, IPv6 will be enabled and an additional IPv6 address configured on the host's VM tap(4) interface whenever you create it with "local interface" / -L. - The IPv6 address is derived from the configured prefix and the IPv4 address of the local interface on the VM side. This way it embeds the VM and interface Id and you can even pf af-to it to IPv4 again! ``` vm_priv_ifconfig: interface tap0 address 100.64.9.2/31 vm_priv_ifconfig: interface tap0 address fdfc:6be5:806:930a:6440:903:0:1/96 100.64.9.3 ``` - The resulting address is suitable for rad(8) - just run "ifconfig vio0 inet6 autoconf" in the guest and you'll get your /96 IPv6 address. ``` vio0: flags=208b43 mtu 1500 lladdr fe:e1:bb:d1:88:4f index 1 priority 0 llprio 3 groups: egress media: Ethernet autoselect status: active inet 100.64.9.3 netmask 0xfffe inet6 fe80::7a1f:6128:505d:4ea5%vio0 prefixlen 64 scopeid 0x1 inet6 fdfc:6be5:806:930a:6440:903:b11c:516 prefixlen 96 autoconf autoconfprivacy pltime 86063 vltime 604794 inet6 fdfc:6be5:806:930a:6440:903:d457:347a prefixlen 96 autoconf pltime 604794 vltime 2591994 ``` - The only problem is that the IPv6 address is nondeterministic where you cannot guess the VM's IPv6 address "from the outside" (32 bits of entropy for the guest IP). It tried it with a /127 prefix but slaacd/rad don't handle this very well as it has a 50% chance of creating a duplicate with the host's IP. I didn't attempt to "fix" it as it would probably be incompatible with other rtsol clients. So I eventually decided that this is not important as I would still use the IPv4 address to log in - the IPv6 address is primarily used for outbound connections. OK? Reyk Index: usr.sbin/vmd/config.c === RCS file: /cvs/src/usr.sbin/vmd/config.c,v retrieving revision 1.54 diff -u -p -u -p -r1.54 config.c --- usr.sbin/vmd/config.c 26 Oct 2018 11:24:45 - 1.54 +++ usr.sbin/vmd/config.c 16 Nov 2018 15:53:10 - @@ -42,17 +42,40 @@ /* Supported bridge types */ const char *vmd_descsw[] = { "switch", "bridge", NULL }; +int config_init_localprefix(struct vmd_config *); + +int +config_init_localprefix(struct vmd_config *cfg) +{ + struct sockaddr_in6 *sin6; + + if (host(VMD_DHCP_PREFIX, &cfg->cfg_localprefix) == -1) + return (-1); + + if (host(VMD_ULA_PREFIX, &cfg->cfg_localprefix6) == -1) + return (-1); + /* Randomize the 56 bits "Global ID" and "Subnet ID" */ + sin6 = ss2sin6(&cfg->cfg_localprefix6.ss); + arc4random_buf(&sin6->sin6_addr.s6_addr[1], 7); + + /* IPv6 is disabled by default */ + cfg->cfg_flags &= ~VMD_CFG_INET6; + + return (0); +} + int config_init(struct vmd *env) { - struct privsep *ps = &env->vmd_ps; - unsigned int what; + struct privsep *ps = &env->vmd_ps; + unsigned int what; /* Global configuration */ ps->ps_what[PROC_PARENT] = CONFIG_ALL; ps->ps_what[PROC_VMM] = CONFIG_VMS; - if (host(VMD_DHCP_PREFIX, &env->vmd_cfg.cfg_localprefix) == -1) + /* Local prefix */ + if (config_init_localprefix(&env->vmd_cfg) == -1) return (-1); /* Other configuration */ @@ -90,7 +113,7 @@ config_purge(struct vmd *env, unsigned i __func__, ps->ps_title[privsep_process]); /* Reset global configuration (prefix was verified before) */ - (void)host(VMD_DHCP_PREFIX, &env->vmd_cfg.cfg_localprefix); + config_init_localprefix(&env->vmd_cfg); /* Reset other configuration */ what = ps->ps_what[privsep_process] & reset; Index: usr.sbin/vmd/dhcp.c === RCS file: /cvs/src/usr.sbin/vmd/dhcp.c,v retrieving revision 1.5 diff -u -p -u -p -r1.5 dhcp.c --- usr.sbin/vmd/dhcp.c 17 Aug 2018 07:12:28 - 1.5 +++ usr.sbin/vmd/dhcp.c 16 Nov 2