Re: vmd: add support for local inet6 interfaces

2018-11-20 Thread Carlos Cardenas
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

2018-11-20 Thread Reyk Floeter
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

2018-11-17 Thread Carlos Cardenas
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

2018-11-16 Thread Reyk Floeter
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