udp, polypath: Make specifying port optional
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Wed, 1 Oct 2014 23:19:34 +0000 (00:19 +0100)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Tue, 21 Oct 2014 00:07:12 +0000 (01:07 +0100)
There is no particular reason why a mobile site with no stable address
ought to have to bind to a particular port.  Doing so in those
configurations can bring in additional complications.

So, make specifying the port optional.

udp_make_socket calls getsockname to find what port number it got.
(We do this unconditionally as that's simplest.)

This has more complicated fallout than appears at first glance.
polypath needs to be able to match disappearances of the interface
address, which is mostly processed in terms of the configured rather
than obtained sockaddr.

In polypath, we need to compare just the addresses when removing an
interface address, because the port will have been assigned later.  We
also use the actual address in logging, rather than the one supplied
by the interface monitor.

To support these changes, we formalise udp_import_socket, and provide
a new `ignoreport' option to iaddr_equal.  The scope of the FAIL and
FAIL_LG macros in udp.c becomes a bit wider.

Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
README
comm-common.h
polypath.c
secnet.h
udp.c
util.c

diff --git a/README b/README
index fd3d31f..414baee 100644 (file)
--- a/README
+++ b/README
@@ -194,8 +194,11 @@ Defines:
   udp (closure => comm closure)
 
 udp: dict argument
-  address (string list): IPv6 or IPv4 addresses to listen and send on
-  port (integer): UDP port to listen and send on
+  address (string list): IPv6 or IPv4 addresses to listen and send on;
+   default is all local addresses
+  port (integer): UDP port to listen and send on; optional if you
+   don't need to have a stable address for your peers to talk to
+   (in which case your site ought probably to have `local-mobile true').
   buffer (buffer closure): buffer for incoming packets
   authbind (string): optional, path to authbind-helper program
 
index aa757e1..5087ad9 100644 (file)
@@ -89,7 +89,12 @@ struct udpcommon {
 
 bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
                       int failmsgclass);
-  /* Fills in us->fd.  Logs any errors with lg_[v]perror. */
+  /* Caller should have filled in ->addr.  Fills in us->fd,
+     ->experienced; updates ->addr.  Logs any errors with lg_[v]perror. */
+bool_t udp_import_socket(struct udpcommon *uc, struct udpsock *us,
+                        int failmsgclass, int fd);
+  /* Like udp_make_socket, but caller provides fd.  fd is not closed
+     on error */
 
 void udp_destroy_socket(struct udpcommon *uc, struct udpsock *us);
   /* Idempotent.  No errors are possible. */
@@ -107,7 +112,7 @@ void udp_socks_childpersist(struct udpcommon *uc, struct udpsocks *socks);
 #define UDP_APPLY_STANDARD(st,uc,desc)                                 \
     (uc)->use_proxy=False;                                             \
     (uc)->authbind=dict_read_string(d,"authbind",False,"udp",(uc)->cc.loc); \
-    (uc)->port=dict_read_number(d,"port",True,"udp",(uc)->cc.loc,0)
+    (uc)->port=dict_read_number(d,"port",False,"udp",(uc)->cc.loc,0)
     /* void UDP_APPLY_STANDARD(SOMETHING *st, struct udpcommon *uc,
      *                         const char *desc);
      *   // Expects in scope:  dict_t *d=...;   as from COMM_APPLY_STANDARD
index 48d06a1..9d5c1b9 100644 (file)
@@ -336,21 +336,23 @@ static void polypath_record_ifaddr(struct polypath *st,
            bool_t ok=polypath_make_socket(st,bad,badctx, us,ifname);
            if (!ok) goto out;
        } else {
-           FILLZERO(us->experienced);
-           us->fd=fd;
+           bool_t ok=udp_import_socket(uc,us,M_WARNING,fd);
+           if (!ok) goto out;
            fd=-1;
        }
        interf->socks.n_socks++;
+       lg_perror(LG,M_INFO,0,"using %s %s",ifname,
+                 iaddr_to_string(&us->addr));
        us=0; /* do not destroy this socket during `out' */
-       lg_perror(LG,M_INFO,0,"using %s %s",ifname,ifaddr);
     } else {
        int i;
        for (i=0; i<interf->socks.n_socks; i++)
-           if (!memcmp(&interf->socks.socks[i].addr,ia,sizeof(*ia)))
+           if (iaddr_equal(&interf->socks.socks[i].addr,ia,True))
                goto address_remove_found;
        BAD("address to remove not found");
     address_remove_found:
-       lg_perror(LG,M_INFO,0,"removed %s %s",ifname,ifaddr);
+       lg_perror(LG,M_INFO,0,"removed %s %s",ifname,
+                 iaddr_to_string(&interf->socks.socks[i].addr));
        udp_destroy_socket(&st->uc,&interf->socks.socks[i]);
        interf->socks.socks[i]=
            interf->socks.socks[--interf->socks.n_socks];
index eb250a4..96717ae 100644 (file)
--- a/secnet.h
+++ b/secnet.h
@@ -431,7 +431,8 @@ struct comm_if {
     comm_addr_to_string_fn *addr_to_string;
 };
 
-bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib);
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib,
+                  bool_t ignoreport);
 
 static inline const char *comm_addr_to_string(const struct comm_addr *ca)
 {
@@ -441,7 +442,7 @@ static inline const char *comm_addr_to_string(const struct comm_addr *ca)
 static inline bool_t comm_addr_equal(const struct comm_addr *a,
                                     const struct comm_addr *b)
 {
-    return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia);
+    return a->comm==b->comm && iaddr_equal(&a->ia,&b->ia,False);
 }
 
 /* LOG interface */
diff --git a/udp.c b/udp.c
index e62f5c1..aef962d 100644 (file)
--- a/udp.c
+++ b/udp.c
@@ -132,7 +132,7 @@ static void udp_socks_afterpoll(void *state, struct pollfd *fds, int nfds)
                    /* Check that the packet came from our poxy server;
                       we shouldn't be contacted directly by anybody else
                       (since they can trivially forge source addresses) */
-                   if (!iaddr_equal(&from,&uc->proxy)) {
+                   if (!iaddr_equal(&from,&uc->proxy,False)) {
                        Message(M_INFO,"udp: received packet that's not "
                                "from the proxy\n");
                        BUF_FREE(cc->rbuf);
@@ -227,6 +227,34 @@ void udp_destroy_socket(struct udpcommon *uc, struct udpsock *us)
     }
 }
 
+#define FAIL_LG 0, cc->cl.description, &cc->loc, failmsgclass
+#define FAIL(...) do{                                          \
+        lg_perror(FAIL_LG,errno,__VA_ARGS__);  \
+       goto failed;                                            \
+    }while(0)
+
+static bool_t record_socket_gotaddr(struct udpcommon *uc, struct udpsock *us,
+                                   int failmsgclass)
+{
+    struct commcommon *cc=&uc->cc;
+    socklen_t salen=sizeof(us->addr);
+    int r=getsockname(us->fd,&us->addr.sa,&salen);
+    if (r) FAIL("getsockname()");
+    if (salen>sizeof(us->addr)) { errno=0; FAIL("getsockname() length"); }
+    return True;
+
+ failed:
+    return False;
+}
+
+bool_t udp_import_socket(struct udpcommon *uc, struct udpsock *us,
+                        int failmsgclass, int fd)
+{
+    FILLZERO(us->experienced);
+    us->fd=fd;
+    return record_socket_gotaddr(uc,us,failmsgclass);
+}
+
 bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
                       int failmsgclass)
 {
@@ -234,12 +262,6 @@ bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
     struct commcommon *cc=&uc->cc;
     us->fd=-1;
 
-#define FAIL_LG 0, cc->cl.description, &cc->loc, failmsgclass
-#define FAIL(...) do{                                          \
-        lg_perror(FAIL_LG,errno,__VA_ARGS__);  \
-       goto failed;                                            \
-    }while(0)
-
     FILLZERO(us->experienced);
     us->fd=socket(addr->sa.sa_family, SOCK_DGRAM, IPPROTO_UDP);
     if (us->fd<0) FAIL("socket");
@@ -318,14 +340,18 @@ bool_t udp_make_socket(struct udpcommon *uc, struct udpsock *us,
        if (bind(us->fd, &addr->sa, iaddr_socklen(addr))!=0)
            FAIL("bind (%s)",iaddr_to_string(addr));
     }
+
+    bool_t ok=record_socket_gotaddr(uc,us,failmsgclass);
+    if (!ok) goto failed;
+
     return True;
 
 failed:
     udp_destroy_socket(uc,us);
     return False;
+}
 
 #undef FAIL
-}
 
 void udp_socks_register(struct udpcommon *uc, struct udpsocks *socks)
 {
diff --git a/util.c b/util.c
index d843859..803098c 100644 (file)
--- a/util.c
+++ b/util.c
@@ -591,19 +591,22 @@ const char *iaddr_to_string(const union iaddr *ia)
     return bufs[b];
 }
 
-bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib)
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib,
+                  bool_t ignoreport)
 {
     if (ia->sa.sa_family != ib->sa.sa_family)
        return 0;
     switch (ia->sa.sa_family) {
     case AF_INET:
        return ia->sin.sin_addr.s_addr == ib->sin.sin_addr.s_addr
-           && ia->sin.sin_port        == ib->sin.sin_port;
+           && (ignoreport ||
+              ia->sin.sin_port        == ib->sin.sin_port);
 #ifdef CONFIG_IPV6
     case AF_INET6:
        return !memcmp(&ia->sin6.sin6_addr, &ib->sin6.sin6_addr, 16)
-           && ia->sin6.sin6_scope_id  == ib->sin6.sin6_scope_id
-           && ia->sin6.sin6_port      == ib->sin6.sin6_port
+          &&  ia->sin6.sin6_scope_id  == ib->sin6.sin6_scope_id
+           && (ignoreport ||
+              ia->sin6.sin6_port      == ib->sin6.sin6_port)
            /* we ignore the flowinfo field */;
 #endif /* CONFIG_IPV6 */
     default: