polypath: Introduce comm-info/dedicated-interface-addr
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 23 Apr 2017 11:36:09 +0000 (12:36 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Sun, 23 Apr 2017 17:06:21 +0000 (18:06 +0100)
Also, rename `interfs' to `interfs_general' in struct polypath, to
ensure we found everywhere this list is processed.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
README
polypath.c

diff --git a/README b/README
index 424f756..e56c444 100644 (file)
--- a/README
+++ b/README
@@ -236,14 +236,18 @@ polypath: dict argument
   buffer (buffer closure): buffer for incoming packets
   authbind (string): optional, path to authbind-helper program
   max-interfaces (number): optional, max number of different interfaces to
-   use (also, maximum steady-state amount of packet multiplication)
+   use (also, maximum steady-state amount of packet multiplication);
+   interfaces marked with `@' do not count.
   interfaces (string list): which interfaces to process; each entry is
-   optionally `!' or `+' followed by a glob pattern (which is applied to a
-   prospective interface using fnmatch with no flags).  If no list is
-   specified, or the list ends with a `!' entry, a default list is
-   used/appended: "!tun*","!tap*","!sl*","!userv*","!lo","*".  Patterns
-   which do not start with `*' or an alphanumeric need to be preceded
-   by `!' or `+'.
+   optionally `!' or `+' or `@' followed by a glob pattern (which is
+   applied to a prospective interface using fnmatch with no flags).
+   `+' or nothing means to process normally. `!' means to ignore;
+   `@' means to use only in conjunction with dedicated-interface-addr.
+   If no list is specified, or the list ends with a `!' entry, a
+   default list is used/appended:
+   "!tun*","!tap*","!sl*","!userv*","!lo","@hippo*","*".
+   Patterns which do not start with `*' or an alphanumeric need to be
+   preceded by `!' or `+' or `@'.
   monitor-command (string list): Program to use to monitor appearance
    and disappearance of addresses on local network interfaces.  Should
    produce lines of the form `+|-<ifname> 4|6 <addr>' where <addr> is
@@ -272,6 +276,14 @@ parameter set to `true'.  When the local site site is not marked
 mobile the address selection machinery might fixate on an unsuitable
 address.
 
+polypath takes site-specific informtion as passed to the `comm-info'
+site closure parameter.  The entries understood in the dictionary
+are:
+  dedicated-interface-addr (string): IPv4 or IPv6 address
+   literal.  Interfaces specified with `@' in `interfaces' will be
+   used for the corresponding site iff the interface local address
+   is this address.
+
 For an interface to work with polypath, it must either have a suitable
 default route, or be a point-to-point interface.  In the general case
 this might mean that the host would have to have multiple default
@@ -446,7 +458,7 @@ site: dict argument
     to 0, the default is to use the local private link mtu.
   comm-info (dict): Information for the comm, used when this site
     wants to transmit.  If the comm does not support this, it is
-    ignored.  (Currently nothing uses this.)
+    ignored.
 
 Links involving mobile peers have some different tuning parameter
 default values, which are generally more aggressive about retrying key
index d0c1400..1d73a0a 100644 (file)
@@ -45,7 +45,8 @@ struct polypath {
     const char *const *ifname_pats;
     const char *const *monitor_command;
     bool_t permit_loopback;
-    LIST_HEAD(interf_list, interf) interfs;
+    LIST_HEAD(interf_list, interf) interfs_general;
+    struct interf_list interfs_dedicated;
     struct buffer_if lbuf;
     int monitor_fd;
     pid_t monitor_pid;
@@ -53,6 +54,10 @@ struct polypath {
     int privsep_ipcsock_fd;
 };
 
+struct comm_clientinfo {
+    union iaddr dedicated; /* might be AF_UNSPEC */
+};
+
 static void polypath_phase_shutdown(void *sst, uint32_t newphase);
 
 #define LG 0, st->uc.cc.cl.description, &st->uc.cc.loc
@@ -61,7 +66,7 @@ static const char *const default_loopback_ifname_pats[] = {
     "!lo", 0
 };
 static const char *const default_ifname_pats[] = {
-    "!tun*","!tap*","!sl*","!userv*", "*", 0
+    "!tun*","!tap*","!sl*","!userv*", "@hippo*", "*", 0
 };
 
 static const char *const default_monitor_command[] = {
@@ -119,6 +124,21 @@ static char ifname_wanted(struct polypath *st, struct cloc loc,
     abort();
 }
 
+static struct comm_clientinfo *polypath_clientinfo(void *state,
+                                    dict_t *dict, struct cloc cloc) {
+    struct comm_clientinfo *clientinfo;
+
+    NEW(clientinfo);
+    FILLZERO(*clientinfo);
+    clientinfo->dedicated.sa.sa_family=AF_UNSPEC;
+
+    item_t *item = dict_find_item(dict,"dedicated-interface-addr",
+                                 False,"polypath",cloc);
+    if (item) string_item_to_iaddr(item,0,&clientinfo->dedicated,
+                                  "polypath");
+    return clientinfo;
+}
+    
 static int polypath_beforepoll(void *state, struct pollfd *fds, int *nfds_io,
                               int *timeout_io)
 {
@@ -331,7 +351,8 @@ static void polypath_record_ifaddr(struct polypath *st,
 
     struct interf_list *interfs;
     switch (want) {
-    case '+':  interfs=&st->interfs;            max_interfs=st->max_interfs;
+    case '+':  interfs=&st->interfs_general;    max_interfs=st->max_interfs;
+    case '@':  interfs=&st->interfs_dedicated;  max_interfs=INT_MAX;
     default:   fatal("polypath: got bad want (%#x, %s)", want, ifname);
     }
 
@@ -457,14 +478,18 @@ static void polypath_sendmsg_interf(struct polypath *st,
                                    struct interf *interf,
                                    struct buffer_if *buf,
                                    const struct comm_addr *dest,
+                                   const union iaddr *dedicated,
                                    bool_t *allreasonable)
 {
     int i;
     int af=dest->ia.sa.sa_family;
-    bool_t attempted=False, reasonable=False;
+    bool_t wanted=False, attempted=False, reasonable=False;
 
     for (i=0; i<interf->socks.n_socks; i++) {
        struct udpsock *us=&interf->socks.socks[i];
+       if (dedicated && !iaddr_equal(dedicated, &us->addr, True))
+           continue;
+       wanted=True;
        if (af != us->addr.sa.sa_family)
            continue;
        attempted=True;
@@ -482,6 +507,9 @@ static void polypath_sendmsg_interf(struct polypath *st,
                  interf->name,iaddr_to_string(&us->addr),
                  buf->size,iaddr_to_string(&dest->ia));
     }
+    if (!wanted)
+       return;
+
     if (!attempted)
        if (!interf->experienced_xmit_noaf[af]++)
            lg_perror(LG,M_WARNING,0,
@@ -499,9 +527,15 @@ static bool_t polypath_sendmsg(void *commst, struct buffer_if *buf,
     struct interf *interf;
     bool_t allreasonable=True;
 
-    LIST_FOREACH(interf,&st->interfs,entry) {
+    LIST_FOREACH(interf,&st->interfs_general,entry) {
        polypath_sendmsg_interf(st,interf,buf,dest,
-                               &allreasonable);
+                               0, &allreasonable);
+    }
+    if (clientinfo && clientinfo->dedicated.sa.sa_family != AF_UNSPEC) {
+       LIST_FOREACH(interf,&st->interfs_dedicated,entry) {
+           polypath_sendmsg_interf(st,interf,buf,dest,
+                                   &clientinfo->dedicated, &allreasonable);
+       }
     }
     return allreasonable;
 }
@@ -588,7 +622,7 @@ struct privsep_mdata {
     bool_t add;
     char ifname[100];
     union iaddr ia;
-    char want; /* `+', for now */
+    char want; /* `+' or `@' */
 };
 
 static void papp_bad(struct polypath *st, void *badctx,
@@ -836,7 +870,9 @@ static void polypath_phase_childpersist(void *sst, uint32_t newphase)
     struct polypath *st=sst;
     struct interf *interf;
 
-    LIST_FOREACH(interf,&st->interfs,entry)
+    LIST_FOREACH(interf,&st->interfs_general,entry)
+       udp_socks_childpersist(&st->uc,&interf->socks);
+    LIST_FOREACH(interf,&st->interfs_dedicated,entry)
        udp_socks_childpersist(&st->uc,&interf->socks);
 }
 
@@ -854,6 +890,8 @@ static list_t *polypath_apply(closure_t *self, struct cloc loc,
     COMM_APPLY_STANDARD(st,&st->uc.cc,"polypath",args);
     UDP_APPLY_STANDARD(st,&st->uc,"polypath");
 
+    st->uc.cc.ops.clientinfo = polypath_clientinfo;
+
     struct udpcommon *uc=&st->uc;
     struct commcommon *cc=&uc->cc;
 
@@ -873,7 +911,8 @@ static list_t *polypath_apply(closure_t *self, struct cloc loc,
     st->permit_loopback=dict_read_bool(d,"permit-loopback",False,
                                       "polypath",cc->loc,False);
 
-    LIST_INIT(&st->interfs);
+    LIST_INIT(&st->interfs_general);
+    LIST_INIT(&st->interfs_dedicated);
     buffer_new(&st->lbuf,ADNS_ADDR2TEXT_BUFLEN+100);
     BUF_ALLOC(&st->lbuf,"polypath lbuf");