chiark / gitweb /
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 fd3d31f7135f1c051535a9c5b61fbe756e8d5596..414baee6caccaeb680e83617c455f176015660e6 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 aa757e1eee851ab52240fab32f0ad4ab4b06581d..5087ad9eb9e690010ef6f6b52bab01b464470373 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 48d06a1308ef3924771285163c45922678a3c666..9d5c1b9990e80ad4c58b3294584dfad57c01ca85 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 eb250a4a4fc3c38b3ababaef20ba595d23b9fa09..96717aea61eadd6ab18a05120bbe45dd1b19e67b 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 e62f5c146332852fb9a4d083d50b2ecce0e15c14..aef962daa9d8cb03985ad5536238d466963aa887 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 d843859f40dcb5fe6593592547888c98b63bbda2..803098cb2b81183eae8161a963ff27d7c0c5c8d6 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: