diff -u -r pptp-1.7.2/pptp.c ../pptp-linux-1.7.2/pptp.c
--- pptp-1.7.2/pptp.c	2008-05-14 16:03:55.000000000 +0930
+++ ../pptp-linux-1.7.2/pptp.c	2015-07-18 02:17:00.000000000 +0930
@@ -252,7 +252,7 @@
                 } else if (option_index == 6) {/* --logstring */
                     log_string = strdup(optarg);
                 } else if (option_index == 7) {/* --localbind */ 
-                    if (inet_pton(AF_INET, optarg, (void *) &localbind) < 1) {
+                    if (!get_device_address(AF_INET, optarg, (void *) &localbind) && inet_pton(AF_INET, optarg, (void *) &localbind) < 1) {
                         fprintf(stderr, "Local bind address %s invalid\n", 
 				optarg);
                         log("Local bind address %s invalid\n", optarg);
@@ -316,6 +316,10 @@
     /* Now we have the peer address, bind the GRE socket early,
        before starting pppd. This prevents the ICMP Unreachable bug
        documented in <1026868263.2855.67.camel@jander> */
+    /* Note that if --localbind option is specified via device,
+       and if the device address changes, the gre_fd will become
+       invalid and we'll have to abort, which is not such a bad
+       thing. */
     gre_fd = pptp_gre_bind(inetaddr);
     if (gre_fd < 0) {
         close(callmgr_sock);
diff -u -r pptp-1.7.2/pptp_callmgr.c ../pptp-linux-1.7.2/pptp_callmgr.c
--- pptp-1.7.2/pptp_callmgr.c	2008-05-14 16:03:55.000000000 +0930
+++ ../pptp-linux-1.7.2/pptp_callmgr.c	2015-07-18 04:20:11.000000000 +0930
@@ -297,6 +297,7 @@
         vector_destroy(call_list);
     }
 cleanup:
+    routing_end();
     signal(SIGINT, callmgr_do_nothing);
     signal(SIGTERM, callmgr_do_nothing);
     close_inetsock(inet_sock, inetaddr);
diff -u -r pptp-1.7.2/routing.c ../pptp-linux-1.7.2/routing.c
--- pptp-1.7.2/routing.c	2008-05-14 16:03:55.000000000 +0930
+++ ../pptp-linux-1.7.2/routing.c	2015-07-18 05:49:47.000000000 +0930
@@ -21,8 +21,12 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <errno.h>
+#include <arpa/inet.h>
 #include "routing.h"
+#include "util.h"
 
 /* route to the server */
 char *route;
@@ -53,27 +57,201 @@
 
 */
 
+
+/*
+
+We allow a device to be specified using -localbind.  When that is used,
+the route we add is a policy route and rule matching packets from our
+address on that device to the server.
+
+We pick a table that is not used and not mentioned in /etc/iproute2/rt_tables.
+
+*/
+static char *svr = 0;	/* ip address of server */
+static char *local = 0;	/* local ip address */
+static char *dev = 0;	/* output device, if specified as -localbind dev */
+static int table = 0;	/* policy routing table, when dev specified */
+
+static char *readline(char *buf, int len, FILE *f) {
+  buf = fgets(buf, len, f);
+  if (buf) {
+     len = strlen(buf);
+     if (len && buf[--len] == '\n') buf[len] = 0;
+  }
+  return buf;
+}
+
+/* delete policy route to server on device specificed by -localbind */
+/* requires local, svr & dev to be set */
+static void del_route(void) {
+  char buf[256];
+  FILE *p;
+  snprintf(buf, sizeof buf-1, "/bin/ip rule show | /bin/fgrep 'from %s to %s '", local, svr);
+//log("running %s", buf);
+  p = popen(buf, "r");
+  if (p) {
+     while (readline(buf, sizeof buf-1, p)) {
+//log("got :%s:", buf);
+       char cmd[256];
+       char *r = strstr(buf, "from ");
+       if (r) {
+          if (log_level)
+             log("deleting rule %s", r);
+          snprintf(cmd, sizeof cmd-1, "/sbin/ip rule del %s", r);
+//log("running %s", cmd);
+          system(cmd);
+       }
+     }
+     pclose(p);
+  }
+  snprintf(buf, sizeof buf-1, "/bin/ip route show table 0 | /bin/grep '^%s \\(.* \\)\\?dev %s'", svr, dev);
+//log("running %s", buf);
+  p = popen(buf, "r");
+  if (p) {
+     while (readline(buf, sizeof buf-1, p)) {
+//log("got :%s:", buf);
+       char cmd[256];
+       if (log_level)
+          log("deleting route %s", buf);
+       snprintf(cmd, sizeof cmd-1, "/sbin/ip route del %s", buf);
+//log("running %s", cmd);
+       system(cmd);
+     }
+     pclose(p);
+  }
+}
+
+/* find available route table to use for a policy route to the server */
+static int get_table(void) {
+  char buf[256];
+  FILE *p;
+  /* now locate unused table for policy route */
+  char inuse[256];	/* would be more efficient to use bits but this is fast */
+  memset(inuse, 0, sizeof inuse);
+  /* prevent use of any table named in /etc/iproute2/rt_tables */
+  p = fopen("/etc/iproute2/rt_tables","r");
+  if (p) {
+     while (readline(buf, sizeof buf-1, p)) {
+//log("got :%s:", buf);
+       char *s = strchr(buf, '#'); if (s) *s = 0;
+       s = strchr(buf, ' '); if (s) *s = 0; 
+       int n = atoi(buf);
+       if (n > 0 && n < sizeof inuse) inuse[n]=1;
+     }
+     fclose(p);
+  }
+  /* prevent use of any table mentioned in ip rule|route show */
+//log("running /sbin/ip rule show; /sbin/ip route show table 0");
+  p = popen("/sbin/ip rule show; /sbin/ip route show table 0", "r");
+  if (p) {
+        while (readline(buf, sizeof buf-1, p)) {
+//log("got :%s:", buf);
+       char *s = strstr(buf, " table ");
+       if (!s) s = strstr(buf, " lookup ");
+       if (s) s = strchr(s+1, ' ');
+       if (s) while (*s == ' ') s++;
+       if (s) {
+          int n = atoi(s);
+          if (n > 0 && n < sizeof inuse) inuse[n]=1;
+       }
+     }
+     pclose(p);
+  }
+  char *u = inuse;
+  while (++u < inuse + sizeof inuse)
+      if (!*u)
+         break;
+  if (u == inuse + sizeof inuse)
+     fatal("no free route table");
+  return u - inuse;
+}
+
 void routing_init(char *ip) {
   char buf[256];
-  snprintf(buf, 255, "/bin/ip route get %s", ip);
+  snprintf(buf, sizeof buf-1, "/bin/ip route get %s", ip);
+  if (dev) {
+     int len = strlen(buf);
+     svr = strdup(ip);	/* save copy of inet_ntoa's value (server address) */
+     if (!svr) fatal("strdup(): %s", strerror(errno));
+//log("svr is %s", svr);
+     snprintf(buf+len, sizeof buf-len-1, " from %s dev %s", local, dev);
+     /* old route could be left by a prior, killed pptp */
+     del_route();
+     table = get_table();
+//log("table is %d", table);
+  }
+//log("running %s", buf);
   FILE *p = popen(buf, "r");
-  fgets(buf, 255, p);
-  /* TODO: check for failure of fgets */
-  route = strdup(buf);
-  pclose(p);
-  /* TODO: check for failure of command */
+  if (p) {
+     if (readline(buf, sizeof buf-1, p))
+//log("got :%s:", buf),
+        route = strdup(buf);
+     pclose(p);
+  }
 }
 
 void routing_start() {
   char buf[256];
-  snprintf(buf, 255, "/bin/ip route replace %s", route);
-  FILE *p = popen(buf, "r");
-  pclose(p);
+  if (table) {
+     if (log_level) log("adding route %s table %d", route, table);
+     snprintf(buf, sizeof buf-1, "/bin/ip route add %s table %d", route, table);
+//log("running %s", buf);
+     system(buf);
+     if (log_level) log("adding rule from %s to %s table %d", local, svr, table);
+     snprintf(buf, sizeof buf-1, "/bin/ip rule add from %s to %s table %d", local, svr, table);
+//log("running %s", buf);
+     system(buf);
+  } else {
+     snprintf(buf, sizeof buf-1, "/bin/ip route replace %s", route);
+     if (log_level) log("replacing route %s", buf);
+     system(buf);
+  }
 }
 
 void routing_end() {
   char buf[256];
-  snprintf(buf, 255, "/bin/ip route delete %s", route);
+  if (table)
+     del_route();
+  else {
+     snprintf(buf, sizeof buf-1, "/bin/ip route delete %s", route);
+     if (log_level) log("deleting route %s", buf);
+     system(buf);
+  }
+}
+
+/* could be --localbind with device */
+/* if it is, we populate local and dev */
+int get_device_address(int af, const char *arg, void *localbind) {
+  char buf[256];
+  snprintf(buf, sizeof buf-1, "/bin/ip -o addr show %s 2> /dev/null", arg);
+//log("running %s", buf);
   FILE *p = popen(buf, "r");
+  /* TODO: check for failure of command */
+  readline(buf, sizeof buf-1, p);
+//log("got :%s:", buf);
+  /* TODO: check for failure of fgets */
   pclose(p);
+  /* get address from a line like:
+     3: wlan0    inet 192.168.0.21/24 brd 192.168.0.255 scope global wlan0\       valid_lft forever preferred_lft forever */
+  local = strstr(buf, " inet ");
+  if (local) {
+     local += 6;	/* skip over " inet " */
+     while (*local == ' ') local++;
+     char *s = strchr(local, ' ');
+     if (s) *s = 0;
+     s = strchr(local, '/');
+     if (s) *s = 0;
+     local = strdup(local);
+     if (!local) fatal("strdup(): %s", strerror(errno));
+//log("local is %s", local);
+     if (inet_pton(af, local, localbind) > 0) {
+        dev = strdup(arg);
+        if (!dev) fatal("strdup(): %s", strerror(errno));
+//log("dev is %s", dev);
+        if (log_level >= 2)
+           log("local address for %s is %s", dev, local);
+        return 1;
+     }
+  }
+  return 0;
 }
diff -u -r pptp-1.7.2/routing.h ../pptp-linux-1.7.2/routing.h
--- pptp-1.7.2/routing.h	2008-05-14 16:03:55.000000000 +0930
+++ ../pptp-linux-1.7.2/routing.h	2015-07-18 01:42:50.000000000 +0930
@@ -1,3 +1,4 @@
 void routing_init(char *ip);
 void routing_start();
 void routing_end();
+int get_device_address(int af,const char *dev,void *dst);
