I am a bit late to the party, but some more comments below.

On Sun, Jul 09, 2023 at 11:27:20PM -0400, Anthony Coulter wrote:
> Summary of this email:
> 
> 1. I respond to a couple of specific points made by other folks in this
>    thread to clarify what I'm trying to accomplish (set up a couple of
>    ad hoc link-local routes without having to ask my ISP for a larger
>    subnet) and to acknowledge that I said something stupid about pings.
> 
> 2. I abandon my quest to get NDP proxying added to iked and instead ask
>    if we can add a "rtlabel" keyword to iked.conf to make it easier for
>    me to write a separate process that monitors the routing table to
>    detect when the tunnel gets set up.
> 
> 3. I ask three questions about the intended uses of routing labels, the
>    purpose of iked's "cloned routes," and the viability of a routing
>    socket that checks your privileges at the time it is opened instead
>    of the time it is used.
> 
> 4. I provide a first draft of a patch which adds that "rtlabel" keyword.
> 
> 
> === Part I. Responding to the discussion ===
> 
> Andy Bradford wrote:
> 
> >> I would also suggest comparing the "hackiness" of NDP proxying to the
> >> hackiness of NAT, which is how we solve this same problem in IPv4.
> >
> > I realize I'm coming in late to this discussion, and may not actually
> > have anything of value to add, but...
> >
> > I'm not sure how NDP proxying and NAT are related at all. I seems to
> > me that NDP proxying is more akin to proxy ARP than NAT:
> >
> > http://man.openbsd.org/arp#s
> 
> They are related in that they are solutions to similar problems. In
> IPv4 we use NAT to deal with the shortage of IP addresses. In IPv6 we
> can use NDP proxying to deal with a local shortage of IPv6 subnets. My
> purpose in writing the line you quoted was to argue that NDP proxying
> is no more hacky than NAT, and the rest of the email tried to argue
> that it was less hacky. Zack Newman, at least, disagrees, and nobody
> jumped to defend my position. So OK, I will settle for calling them
> equally hacky.
> 
> My goal in this discussion was to either convince someone that adding
> automatic NDP proxying to iked was a good idea, or to at least get
> agreement that it isn't a bad idea so that they would accept the code
> if I wrote it myself. I failed in both of these objectives. But that's
> why it matters to me whether NDP proxying is considered hacky or not.
> If it's hacky, then the iked maintainers will reject a patch that adds
> the ndp-proxy keyword even if I write it myself.
> 
> 
> Zack Newman wrote:
> 
> > Yeah, I don't have the interest to get into it about this; but I find
> > it (informally) inconsistent to take an ideological stance against NAT
> > and not have a similar stance against NDP proxying.
> 
> To this I'll say that my stance against NAT isn't ideological. It's
> just that NAT is more intrusive than NDP proxying. All NDP proxying
> does is tell nearby hosts to update their routing tables to do exactly
> what you want them to do. NAT, on the other hand, rewrites addresses
> and ports so the packet you send out isn't the packet the other end
> receives. And I'm not saying that people shouldn't use NAT for IPv4.
> I just think that in the IPv6 case, if getting more subnets isn't an
> easy affair, NDP proxying is a less-intrusive hack to get your VPN
> client's traffic routed properly than NAT is, and as such, setting it
> up ought to be as convenient and hassle-free as adding rules to pf.
> 
> 
> > Also not sure where you heard that ICMP does not work with NAT. Surely
> > you don't believe that. Go ahead and use ping(8) on any device that
> > relies on NAT to talk to the outside world and witness how it
> > "magically" works. ICMP uses the Query ID in lieu of a port number.
> 
> Yikes, I wasn't thinking clearly. While it's true that an external host
> can't ping the NATted host (it can only ping the server which is doing
> the NAT), that isn't the gist of what I claimed. Yes, you are correct.
> 
> 
> > Will NDP proxying work? Depending on what you want, sure just like NAT
> > will likely work. Relying on a simple routing table is far more ideal.
> > NDP proxying is also vulnerable to NDP cache DoS. You can use your
> > favorite search engine to learn why NDP proxying is not as good as
> > simple routes.
> 
> Thanks for the specific example. I looked into this and it seems that
> my use case might be misunderstood. The NDP cache DoS depends on a
> setup similar to what the "nd-reflector" project (linked to in a
> previous email in this thread) provides: NDP-proxying an entire subnet
> instead of just the one host in question. Under these circumstances,
> an attacker can fill the router's NDP cache with a bunch of
> incorrectly-proxied addresses that don't actually point to anything,
> just by trying to hit a bunch of random addresses in the subnet and
> tricking the NDP proxy into responding to all of them.
> 
> The use case I have in mind is to only proxy an address when it is
> allocated to a client that has connected to the VPN, and to stop
> proxying that address when the client disconnects. That's why I thought
> it was something iked ought to be able to do: when the client connects
> to iked, iked knows what address it assigned the client so it can
> automatically add this address to the router table with the RTF_ANNOUNCE
> flag set (which is all that "ndp -s" does when I add it to the cache
> manually). Since iked also knows when the client disconnects, it would
> be an excellent candidate for removing the router table entry as well.
> Thus at any moment, the router table on the IKEv2 responder is set to
> NDP proxy only those addresses which correspond to connected clients
> for which the "ndp-proxy" configuration flag was set in iked.conf. This
> would not increase the risk of NDP cache DoS attacks any more than
> physically plugging an additional host into the link-local network
> would, because neighbor advertisements are only sent for neighbors that
> actually exist (albeit across a tunnel).
> 
> 
> === Part II. My new approach ===
> 
> Since my proposal to have iked enable NDP proxying itself failed to
> gain traction I looked into other options (that don't involve
> requesting a larger subnet from my ISP and VPS providers). The
> fundamental technical obstacle I have to overcome is allowing a
> separate process to detect when clients connect and disconnect so that
> it can add or remove the RTF_ANNOUNCE cache entry as appropriate.
> 
> Instead of tailing the iked log in /var/log/daemon, which seems awfully
> brittle, my new idea is to open a routing socket and watch to see when
> iked opens and closes the tunnel. (I'm learning about a lot of this as
> I go so ideas that are obvious to you might not be obvious to me.) This
> is still architecturally simple in the sense that my server process can
> do it all with a single routing socket, which it uses both to detect
> the incoming client and to add the NDP cache entry. So *now* my problem
> narrows to figuring out which routing messages correspond to incoming
> VPN clients that need to be proxied. I could hack it to look for
> certain telltale signs of the changes I want (i.e. an individual
> address from a particular subnet being added with a local destination
> and particular flags set) but that still looks brittle so I have a
> better plan involving routing labels.
> 
> My new idea still involves a change to iked, but I think this one will
> be less controversial. I now propose the addition of the "rtlabel"
> keyword to the iked.conf grammar:
> 
> ikev2 'server_config' passive esp \
>         from any to dynamic \
>         local 2001:db8:2::1 \
>         srcid server.example.org \
>         config address 2001:db8:2::/64 \
>         tag "ROADW" \
>       rtlabel "vpn_tunnel"
> 
> All this keyword does is cause ikev2 to add an RTA_LABEL with the value
> "vpn_tunnel" to the RTM_ADD and RTM_DELETE updates that it performs
> when setting up and tearing down this particular tunnel. This is no
> more intrusive than the "tag" keyword that appears on the preceding
> line---it just adds internal labels to messages that flow through the
> kernel so that other processes can hook in and do whatever custom
> behaviors they want. I've already verified that RTM_DELETE messages
> can carry routing labels even though the label doesn't get added to the
> table.
> 
> === Part III. Some questions ===
> 
> I have a couple of questions about the routing labels and iked:
> 
> 1. Right now slaacd automatically labels all the routes it creates with
> "slaacd". As a result, I'm tempted to tag *all* of iked's routing
> messages with "iked" by default (even routing messages that aren't
> related to the tunnels) since the user already has to be aware that
> some labels are taken. As an added bonus, a casual "route -v show" will
> make it easier to figure out where all the routes are coming from.
> Would this change have support if I did the legwork?

Yes, setting a fixed iked route label seems like a good idea.
I am not convinced we need a per policy config setting.

> 
> 2. What is the purpose of iked's IMSG_VROUTE_CLONE? Apparently this
> looks up the current route to the peer, replaces the destination field
> (which I assume must be either the peer's address or a subnet
> containing the peer's address) with the peer's address, and re-adds it
> to the routing table. What benefit does this provide? I think I
> understand "cloning" in the context of ARP and NDP caches with their
> RTF_CLONING and RTF_CLONED flags, and I recognize the pattern here of
> "take an existing route and re-add a more specific version of it"
> (which isn't what "clone" means anywhere else in the world, but
> whatever). But I don't understand why we would want to do it in this
> context. Maybe it's a trick to make sure that encapsulated IPsec
> packets don't get routed into the same tunnel a second time, in the
> instance that the peer's address is contained in the subnet that is
> supposed to be tunneled. But I don't see how that trick would work
> for transport-mode IPsec, where the destination address is the same
> before and after encapsulation---the cloned route seems to get the
> same priority (IKED_VROUTE_PRIO) as the tunnel. So what does this
> cloned route accomplish?

We sometimes set a higher than the rest prio default route to route all
traffic trough the VPN. This of course also overrides our route to the
IKEv2 peer, so we add an explicit peer route with the same prio.

> 
> 3. It's a common pattern in OpenBSD to "hoist" privileged operations to
> program startup but it isn't possible to do this with routing sockets,
> since the kernel checks your effective user ID at time of use rather
> than at time of open. So here's an idea: what if we use the third
> argument to socket(2) to pass a new "protocol family" PFWROUTE, so that
>       socket(AF_ROUTE, SOCK_RAW, PF_WROUTE)
> returns a routing socket that continues to work even after you've
> dropped privileges or passed the socket to another process with sendfd?
> I'm not confident of this, but I believe that the only reason slaacd's
> parent process runs as root and not _slaacd is to allow it to make
> routing table changes. My NDP proxy setter-upper process would have the
> same issue: I can't drop privileges because I want to update the
> routing table. Would this idea get any sort of traction?
> 
> 
> === Part 4. A tentative diff ===
> 
> Below is a rough draft of changes in /usr/src/sbin/iked that show what
> I have in mind. The change to the iked.8 man page was just something
> that I noticed in the code that wasn't documented. As for the rest of
> the diff there are a number of things I'm doing wrong at the moment:

The man page diff looks ok.

> 
> 1. Search for "goto hack" to see how I currently deal with the fact
>    that the IMSG_VROUTE_{ADD,CLONE,DELETE} messages don't have a nice
>    bitfield like rtm_addrs. The correct approach is probably to add
>    an addrs bitfield to the IMSG format.
> 
> 2. The parent process doesn't remember the routing labels so when iked
>    shuts down and the parent process calls vroute_cleanup, the labels
>    are missing.
> 
> 3. I don't have a solid plan yet on which routes would get whicho
>    labels. In this draft the IMSG_VROUTE_CLONE route picks up the
>    routing label corresponding to the tunnel, but I suspect that in the
>    final draft, clone routes will get the default "iked" label. On the
>    other hand, in the final draft RTM_NEWADDR and RTM_DELADDR messages
>    that add and delete addresses on an interface probably *will* get
>    the same policy-specific tag that the tunnnel routes get. There are
>    other routing messages that I haven't even touched yet. Whether I
>    continue with all the other routes depends on what the mailing list
>    says about what's likely to be accepted. What matters to me is that
>    I have an easy way to identify the route corresponding to a recently
>    added tunnel. (The addition of an address to an interface doesn't
>    matter to me because that happens on the client but the NDP proxying
>    happens on the server. But I'm thinking it should get the same
>    rtlabel in case someone else ends up having a use for it, since my
>    impression is that route labels are essentially free.)
> 
> If I continued work in this direction, would it be likely to get
> merged?
> 
> Thanks and regards,
> Anthony Coulter
> 
> 
> 
> 
> diff --git iked.8 iked.8
> index 7134e54f843..8af88b529c8 100644
> --- iked.8
> +++ iked.8
> @@ -110,7 +110,7 @@ negotiate NAT-Traversal with the peers.
>  .It Fl V
>  Show the version and exit.
>  .It Fl v
> -Produce more verbose output.
> +Produce more verbose output. Repeating this argument increases the verbosity.
>  .El
>  .Sh PUBLIC KEY AUTHENTICATION
>  It is possible to store trusted public keys to make them directly
> diff --git iked.conf.5 iked.conf.5
> index 5ca57e4767e..2189918329d 100644
> --- iked.conf.5
> +++ iked.conf.5
> @@ -775,6 +775,13 @@ for filtering and monitoring.
>  The traffic will be blocked if the specified
>  .Ar interface
>  does not exist.
> +.Pp
> +.It Ic rtlabel Ar string
> +Set an
> +.Dv RTA_LABEL
> +of
> +.Ar string
> +in the routing socket messages that create and delete the tunneled routes.
>  .El
>  .Sh PACKET FILTERING
>  IPsec traffic appears unencrypted on the
> diff --git iked.h iked.h
> index dc97f6560f9..91ad6f58653 100644
> --- iked.h
> +++ iked.h
> @@ -21,6 +21,7 @@
>  #include <sys/tree.h>
>  #include <sys/queue.h>
>  #include <arpa/inet.h>
> +#include <net/route.h>
>  #include <limits.h>
>  #include <imsg.h>
>  
> @@ -33,6 +34,8 @@
>  #define MINIMUM(a,b) (((a)<(b))?(a):(b))
>  #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
>  
> +#define IKED_RTLABEL "iked"
> +
>  #ifndef IKED_H
>  #define IKED_H
>  
> @@ -301,6 +304,8 @@ struct iked_policy {
>  
>       struct iked_sapeers              pol_sapeers;
>  
> +     char                             pol_rtlabel[RTLABEL_LEN];
> +
>       TAILQ_ENTRY(iked_policy)         pol_entry;
>  };
>  TAILQ_HEAD(iked_policies, iked_policy);
> @@ -1043,11 +1048,11 @@ int vroute_getaddr(struct iked *, struct imsg *);
>  int vroute_setdns(struct iked *, int, struct sockaddr *, unsigned int);
>  int vroute_getdns(struct iked *, struct imsg *);
>  int vroute_setaddroute(struct iked *, uint8_t, struct sockaddr *,
> -    uint8_t, struct sockaddr *);
> +    uint8_t, struct sockaddr *, const char *);
>  int vroute_setcloneroute(struct iked *, uint8_t, struct sockaddr *,
> -    uint8_t, struct sockaddr *);
> +    uint8_t, struct sockaddr *, const char *);
>  int vroute_setdelroute(struct iked *, uint8_t, struct sockaddr *,
> -    uint8_t, struct sockaddr *);
> +    uint8_t, struct sockaddr *, const char *);
>  int vroute_getroute(struct iked *, struct imsg *);
>  int vroute_getcloneroute(struct iked *, struct imsg *);
>  
> diff --git parse.y parse.y
> index 075981db320..3199da5e2f4 100644
> --- parse.y
> +++ parse.y
> @@ -381,7 +381,7 @@ int                        create_ike(char *, int, struct 
> ipsec_addr_wrap *,
>                           uint8_t, char *, char *,
>                           uint32_t, struct iked_lifetime *,
>                           struct iked_auth *, struct ipsec_filters *,
> -                         struct ipsec_addr_wrap *, char *);
> +                         struct ipsec_addr_wrap *, char *, char *);
>  int                   create_user(const char *, const char *);
>  int                   get_id_type(char *);
>  uint8_t                       x2i(unsigned char *);
> @@ -445,10 +445,10 @@ typedef struct {
>  %token       VENDORID NOVENDORID
>  %token       TOLERATE MAXAGE DYNAMIC
>  %token       CERTPARTIALCHAIN
> -%token       REQUEST IFACE
> +%token       REQUEST IFACE RTLABEL
>  %token       <v.string>              STRING
>  %token       <v.number>              NUMBER
> -%type        <v.string>              string
> +%type        <v.string>              string rtlabel
>  %type        <v.satype>              satype
>  %type        <v.proto>               proto proto_list protoval
>  %type        <v.hosts>               hosts hosts_list
> @@ -550,16 +550,20 @@ user            : USER STRING STRING            {
>  
>  ikev2rule    : IKEV2 name ikeflags satype af proto rdomain hosts_list peers
>                   ike_sas child_sas ids ikelifetime lifetime ikeauth ikecfg
> -                 iface filters {
> +                 iface filters rtlabel {
>                       if (create_ike($2, $5, $6, $7, $8, &$9, $10, $11, $4,
>                           $3, $12.srcid, $12.dstid, $13, &$14, &$15,
> -                         $18, $16, $17) == -1) {
> +                         $18, $16, $17, $19) == -1) {
>                               yyerror("create_ike failed");
>                               YYERROR;
>                       }
>               }
>               ;
>  
> +rtlabel              : /* empty */                   { $$ = NULL; }
> +             | RTLABEL STRING                { $$ = $2; }
> +             ;
> +
>  ikecfg               : /* empty */                   { $$ = NULL; }
>               | ikecfgvals                    { $$ = $1; }
>               ;
> @@ -1390,6 +1394,7 @@ lookup(char *s)
>               { "quick",              QUICK },
>               { "rdomain",            RDOMAIN },
>               { "request",            REQUEST },
> +             { "rtlabel",            RTLABEL },
>               { "sa",                 SA },
>               { "set",                SET },
>               { "skip",               SKIP },
> @@ -2471,7 +2476,7 @@ create_ike(char *name, int af, struct ipsec_addr_wrap 
> *ipproto,
>      uint8_t flags, char *srcid, char *dstid,
>      uint32_t ikelifetime, struct iked_lifetime *lt,
>      struct iked_auth *authtype, struct ipsec_filters *filter,
> -    struct ipsec_addr_wrap *ikecfg, char *iface)
> +    struct ipsec_addr_wrap *ikecfg, char *iface, char *rtlabel)
>  {
>       char                     idstr[IKED_ID_SIZE];
>       struct ipsec_addr_wrap  *ipa, *ipb, *ipp;
> @@ -2897,6 +2902,18 @@ create_ike(char *name, int af, struct ipsec_addr_wrap 
> *ipproto,
>               break;
>       }
>  
> +     bzero(pol.pol_rtlabel, sizeof pol.pol_rtlabel);
> +     if (rtlabel) {
> +             if (strlcpy(pol.pol_rtlabel, rtlabel, RTLABEL_LEN)
> +                 >= RTLABEL_LEN) {
> +                     yyerror("rtlabel \"%s\" too long; max length"
> +                         "is %d\n", rtlabel, RTLABEL_LEN - 1);
> +                     goto done;
> +             }
> +     } else {
> +             strlcpy(pol.pol_rtlabel, IKED_RTLABEL, RTLABEL_LEN);
> +     }
> +
>       log_debug("%s: using %s for peer %s", __func__,
>           print_xf(ikeauth->auth_method, 0, methodxfs), idstr);
>  
> @@ -2957,6 +2974,7 @@ done:
>       free(name);
>       free(srcid);
>       free(dstid);
> +     free(rtlabel);
>       return (ret);
>  }
>  
> diff --git policy.c policy.c
> index 0048b4a9281..5eafb8a3109 100644
> --- policy.c
> +++ policy.c
> @@ -722,12 +722,13 @@ sa_configure_iface(struct iked *env, struct iked_sa 
> *sa, int add)
>       if (add) {
>               /* Add direct route to peer */
>               if (vroute_setcloneroute(env, getrtable(),
> -                 (struct sockaddr *)&sa->sa_peer.addr, 0, NULL))
> +                 (struct sockaddr *)&sa->sa_peer.addr, 0, NULL,
> +                 sa->sa_policy->pol_rtlabel))
>                       return (-1);
>       } else {
>               if (vroute_setdelroute(env, getrtable(),
> -                 (struct sockaddr *)&sa->sa_peer.addr,
> -                 0, NULL))
> +                 (struct sockaddr *)&sa->sa_peer.addr, 0, NULL,
> +                 sa->sa_policy->pol_rtlabel))
>                       return (-1);
>       }
>  
> @@ -752,12 +753,14 @@ sa_configure_iface(struct iked *env, struct iked_sa 
> *sa, int add)
>               if (add) {
>                       if (vroute_setaddroute(env, rdomain,
>                           (struct sockaddr *)&saflow->flow_dst.addr,
> -                         saflow->flow_dst.addr_mask, caddr))
> +                         saflow->flow_dst.addr_mask, caddr,
> +                         sa->sa_policy->pol_rtlabel))
>                               return (-1);
>               } else {
>                       if (vroute_setdelroute(env, rdomain,
>                           (struct sockaddr *)&saflow->flow_dst.addr,
> -                         saflow->flow_dst.addr_mask, caddr))
> +                         saflow->flow_dst.addr_mask, caddr,
> +                         sa->sa_policy->pol_rtlabel))
>                               return (-1);
>               }
>       }
> diff --git print.c print.c
> index 5444f950bff..ba1b6d1ae86 100644
> --- print.c
> +++ print.c
> @@ -25,6 +25,7 @@
>  #include <inttypes.h>
>  #include <stdio.h>
>  #include <stdlib.h>
> +#include <string.h>
>  #include <unistd.h>
>  #include <event.h>
>  
> @@ -239,5 +240,8 @@ print_policy(struct iked_policy *pol)
>       if (pol->pol_tap != 0)
>               print_verbose(" tap \"enc%u\"", pol->pol_tap);
>  
> +     if (strcmp(pol->pol_rtlabel, IKED_RTLABEL) != 0)
> +             print_verbose(" rtlabel \"%s\"", pol->pol_rtlabel);
> +
>       print_verbose("\n");
>  }
> diff --git vroute.c vroute.c
> index 5ef892d61ab..c750d1c469b 100644
> --- vroute.c
> +++ vroute.c
> @@ -41,9 +41,9 @@
>  #define ROUNDUP(a) (a>0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : 
> sizeof(long))
>  
>  int vroute_setroute(struct iked *, uint32_t, struct sockaddr *, uint8_t,
> -    struct sockaddr *, int);
> +    struct sockaddr *, const char *, int);
>  int vroute_doroute(struct iked *, int, int, int, uint8_t, struct sockaddr *,
> -    struct sockaddr *, struct sockaddr *, int *);
> +    struct sockaddr *, struct sockaddr *, struct sockaddr *, int *need_gw);
>  int vroute_doaddr(struct iked *, char *, struct sockaddr *, struct sockaddr 
> *, int);
>  int vroute_dodns(struct iked *, struct sockaddr *, int, unsigned int);
>  void vroute_cleanup(struct iked *);
> @@ -210,7 +210,7 @@ vroute_cleanup(struct iked *env)
>                   route->vr_flags, route->vr_rdomain, RTM_DELETE,
>                   (struct sockaddr *)&route->vr_dest,
>                   (struct sockaddr *)&route->vr_mask,
> -                 NULL, NULL);
> +                 NULL, NULL, NULL);
>               TAILQ_REMOVE(&ivr->ivr_routes, route, vr_entry);
>               free(route);
>       }
> @@ -493,36 +493,37 @@ vroute_removeaddr(struct iked *env, int ifidx, struct 
> sockaddr *addr,
>  
>  int
>  vroute_setaddroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
> -    uint8_t mask, struct sockaddr *ifa)
> +    uint8_t mask, struct sockaddr *ifa, const char *rtlabel)
>  {
> -     return (vroute_setroute(env, rdomain, dst, mask, ifa,
> +     return (vroute_setroute(env, rdomain, dst, mask, ifa, rtlabel,
>           IMSG_VROUTE_ADD));
>  }
>  
>  int
>  vroute_setcloneroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
> -    uint8_t mask, struct sockaddr *addr)
> +    uint8_t mask, struct sockaddr *addr, const char *rtlabel)
>  {
> -     return (vroute_setroute(env, rdomain, dst, mask, addr,
> +     return (vroute_setroute(env, rdomain, dst, mask, addr, rtlabel,
>           IMSG_VROUTE_CLONE));
>  }
>  
>  int
>  vroute_setdelroute(struct iked *env, uint8_t rdomain, struct sockaddr *dst,
> -    uint8_t mask, struct sockaddr *addr)
> +    uint8_t mask, struct sockaddr *addr, const char *rtlabel)
>  {
> -     return (vroute_setroute(env, rdomain, dst, mask, addr,
> +     return (vroute_setroute(env, rdomain, dst, mask, addr, rtlabel,
>           IMSG_VROUTE_DEL));
>  }
>  
>  int
>  vroute_setroute(struct iked *env, uint32_t rdomain, struct sockaddr *dst,
> -    uint8_t mask, struct sockaddr *addr, int type)
> +    uint8_t mask, struct sockaddr *addr, const char *rtlabel, int type)
>  {
>       struct sockaddr_storage  sa;
> +     struct sockaddr_rtlabel  sr;
>       struct sockaddr_in      *in;
>       struct sockaddr_in6     *in6;
> -     struct iovec             iov[5];
> +     struct iovec             iov[6];
>       int                      iovcnt = 0;
>       uint8_t                  af;
>  
> @@ -567,6 +568,14 @@ vroute_setroute(struct iked *env, uint32_t rdomain, 
> struct sockaddr *dst,
>               iovcnt++;
>       }
>  
> +     bzero(&sr, sizeof sr);
> +     sr.sr_len = sizeof sr;
> +     sr.sr_family = AF_UNSPEC;
> +     strlcpy(sr.sr_label, rtlabel, sizeof sr.sr_label);
> +     iov[iovcnt].iov_base = &sr;
> +     iov[iovcnt].iov_len = sr.sr_len;
> +     iovcnt++;
> +
>       return (proc_composev(&env->sc_ps, PROC_PARENT, type, iov, iovcnt));
>  }
>  
> @@ -574,6 +583,7 @@ int
>  vroute_getroute(struct iked *env, struct imsg *imsg)
>  {
>       struct sockaddr         *dest, *mask = NULL, *gateway = NULL;
> +     struct sockaddr         *rtlabel = NULL;
>       uint8_t                 *ptr;
>       size_t                   left;
>       int                      addrs = 0;
> @@ -600,9 +610,11 @@ vroute_getroute(struct iked *env, struct imsg *imsg)
>       addrs |= RTA_DST;
>  
>       flags = RTF_UP | RTF_GATEWAY | RTF_STATIC;
> -     if (left != 0) {
> +     if (left != 0 && left) {
>               if (left < sizeof(struct sockaddr))
>                       return (-1);
> +             if ((struct sockaddr *)ptr == AF_UNSPEC)
> +                     goto hack; /* Not a netmask! */
>               mask = (struct sockaddr *)ptr;
>               if (left < mask->sa_len)
>                       return (-1);
> @@ -624,6 +636,16 @@ vroute_getroute(struct iked *env, struct imsg *imsg)
>               flags |= RTF_HOST;
>       }
>  
> + hack:
> +     if (left < sizeof(struct sockaddr))
> +             return (-1);
> +     rtlabel = (struct sockaddr *)ptr;
> +     if (left < rtlabel->sa_len)
> +             return (-1);
> +     ptr += rtlabel->sa_len;
> +     left -= rtlabel->sa_len;
> +     addrs |= RTA_LABEL;
> +
>       switch(imsg->hdr.type) {
>       case IMSG_VROUTE_ADD:
>               type = RTM_ADD;
> @@ -638,7 +660,7 @@ vroute_getroute(struct iked *env, struct imsg *imsg)
>       else
>               vroute_removeroute(env, rdomain, dest, mask);
>       return (vroute_doroute(env, flags, addrs, rdomain, type,
> -         dest, mask, gateway, NULL));
> +         dest, mask, gateway, rtlabel, NULL));
>  }
>  
>  int
> @@ -648,6 +670,7 @@ vroute_getcloneroute(struct iked *env, struct imsg *imsg)
>       struct sockaddr_storage  dest;
>       struct sockaddr_storage  mask;
>       struct sockaddr_storage  addr;
> +     struct sockaddr_storage  rtlabel;
>       uint8_t                 *ptr;
>       size_t                   left;
>       uint32_t                 rdomain;
> @@ -667,6 +690,7 @@ vroute_getcloneroute(struct iked *env, struct imsg *imsg)
>       bzero(&dest, sizeof(dest));
>       bzero(&mask, sizeof(mask));
>       bzero(&addr, sizeof(addr));
> +     bzero(&rtlabel, sizeof(rtlabel));
>  
>       if (left < sizeof(struct sockaddr))
>               return (-1);
> @@ -677,11 +701,20 @@ vroute_getcloneroute(struct iked *env, struct imsg 
> *imsg)
>       ptr += dst->sa_len;
>       left -= dst->sa_len;
>  
> +     if (left < sizeof(struct sockaddr_rtlabel))
> +             return (-1);
> +     dst = (struct sockaddr *)ptr;
> +     if (left < dst->sa_len)
> +             return (-1);
> +     memcpy(&rtlabel, dst, dst->sa_len);
> +     ptr += dst->sa_len;
> +     left -= dst->sa_len;
> +
>       /* Get route to peer */
>       flags = RTF_UP | RTF_HOST | RTF_STATIC;
>       if (vroute_doroute(env, flags, RTA_DST, rdomain, RTM_GET,
>           (struct sockaddr *)&dest, (struct sockaddr *)&mask,
> -         (struct sockaddr *)&addr, &need_gw))
> +         (struct sockaddr *)&addr, NULL, &need_gw))
>               return (-1);
>  
>       if (need_gw)
> @@ -692,10 +725,11 @@ vroute_getcloneroute(struct iked *env, struct imsg 
> *imsg)
>       vroute_insertroute(env, rdomain, (struct sockaddr *)&dest, NULL);
>  
>       /* Set explicit route to peer with gateway addr*/
> -     addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
> +     addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_LABEL;
>       return (vroute_doroute(env, flags, addrs, rdomain, RTM_ADD,
>           (struct sockaddr *)&dest, (struct sockaddr *)&mask,
> -         (struct sockaddr *)&addr, NULL));
> +         (struct sockaddr *)&addr, (struct sockaddr *)&rtlabel,
> +         NULL));
>  }
>  
>  int
> @@ -767,10 +801,11 @@ vroute_dodns(struct iked *env, struct sockaddr *dns, 
> int add,
>  
>  int
>  vroute_doroute(struct iked *env, int flags, int addrs, int rdomain, uint8_t 
> type,
> -    struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr, int 
> *need_gw)
> +    struct sockaddr *dest, struct sockaddr *mask, struct sockaddr *addr,
> +    struct sockaddr *rtlabel, int *need_gw)
>  {
>       struct vroute_msg        m_rtmsg;
> -     struct iovec             iov[7];
> +     struct iovec             iov[9];
>       struct iked_vroute_sc   *ivr = env->sc_vroute;
>       ssize_t                  len;
>       int                      iovcnt = 0;
> @@ -829,11 +864,24 @@ vroute_doroute(struct iked *env, int flags, int addrs, 
> int rdomain, uint8_t type
>               }
>       }
>  
> +     if (rtm.rtm_addrs & RTA_LABEL) {
> +             iov[iovcnt].iov_base = rtlabel;
> +             iov[iovcnt].iov_len = rtlabel->sa_len;
> +             iovcnt++;
> +             padlen = ROUNDUP(rtlabel->sa_len) - rtlabel->sa_len;
> +             if (padlen > 0) {
> +                     iov[iovcnt].iov_base = &pad;
> +                     iov[iovcnt].iov_len = padlen;
> +                     iovcnt++;
> +             }
> +     }
> +
>       for (i = 0; i < iovcnt; i++)
>               rtm.rtm_msglen += iov[i].iov_len;
>  
>       log_debug("%s: len: %u type: %s rdomain: %d flags %x (%s%s)"
> -         " addrs %x (dst %s mask %s gw %s)", __func__, rtm.rtm_msglen,
> +         " addrs %x (dst %s mask %s gw %s) %s%s",
> +         __func__, rtm.rtm_msglen,
>           type == RTM_ADD ? "RTM_ADD" : type == RTM_DELETE ? "RTM_DELETE" :
>           type == RTM_GET ? "RTM_GET" : "unknown", rdomain,
>           flags,
> @@ -842,7 +890,9 @@ vroute_doroute(struct iked *env, int flags, int addrs, 
> int rdomain, uint8_t type
>           addrs,
>           addrs & RTA_DST ? print_addr(dest) : "<>",
>           addrs & RTA_NETMASK ? print_addr(mask) : "<>",
> -         addrs & RTA_GATEWAY ? print_addr(addr) : "<>");
> +         addrs & RTA_GATEWAY ? print_addr(addr) : "<>",
> +         addrs & RTA_LABEL ? "label " : "",
> +         addrs & RTA_LABEL ? ((struct sockaddr_rtlabel*)rtlabel)->sr_label : 
> "");
>  
>       if (writev(ivr->ivr_rtsock, iov, iovcnt) == -1) {
>               if ((type == RTM_ADD && errno != EEXIST) ||
> 

Reply via email to