Hello,

I've implemented DNS automatic negotiation and configuration in
pppd (RFC1877). Since it is not a standard thing, I made it an
optional feature of pppd. Some parts of the code were taken from ppp
implementation. I would be greatful for testing of this patch and
for any comments and suggestion.

Thanks,

-ip

-- 
If your condition seems to be getting better, it's
probably your doctor getting sick.
Index: pppd/Makefile
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/Makefile,v
retrieving revision 1.19.2.3
diff -u -r1.19.2.3 Makefile
--- pppd/Makefile       13 Dec 2004 13:50:02 -0000      1.19.2.3
+++ pppd/Makefile       25 Dec 2005 17:25:55 -0000
@@ -38,6 +38,9 @@
 DPADD+=        ${LIBCRYPTO}
 .endif
 
+# DNS automatic configuration support
+CFLAGS+=-DNS_NEGOTIATE -DDNS_CONFIGURE
+
 .if defined(RELEASE_CRUNCH)
 # We must create these objects because crunchgen will link them,
 # and we don't want any unused symbols to spoil the final link.
Index: pppd/cbcp.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/cbcp.c,v
retrieving revision 1.4.2.2
diff -u -r1.4.2.2 cbcp.c
--- pppd/cbcp.c 11 Dec 2004 11:23:56 -0000      1.4.2.2
+++ pppd/cbcp.c 25 Dec 2005 14:43:18 -0000
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/types.h>
 #include <sys/time.h>
+#include <netinet/in.h>
 #include <syslog.h>
 
 #include "pppd.h"
Index: pppd/demand.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/demand.c,v
retrieving revision 1.5
diff -u -r1.5 demand.c
--- pppd/demand.c       28 Aug 1999 01:19:02 -0000      1.5
+++ pppd/demand.c       25 Dec 2005 14:38:28 -0000
@@ -28,6 +28,7 @@
 #include <fcntl.h>
 #include <syslog.h>
 #include <netdb.h>
+#include <netinet/in.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/wait.h>
Index: pppd/ipcp.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/ipcp.c,v
retrieving revision 1.12
diff -u -r1.12 ipcp.c
--- pppd/ipcp.c 28 Aug 1999 01:19:03 -0000      1.12
+++ pppd/ipcp.c 27 Dec 2005 16:47:00 -0000
@@ -28,11 +28,15 @@
 #include <stdio.h>
 #include <string.h>
 #include <syslog.h>
+#include <fcntl.h>
 #include <netdb.h>
 #include <sys/param.h>
+#include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
+#include <arpa/inet.h>
+#include <resolv.h>
 
 #include "pppd.h"
 #include "fsm.h"
@@ -49,6 +53,9 @@
 static int cis_received[NUM_PPP];      /* # Conf-Reqs received */
 static int default_route_set[NUM_PPP]; /* Have set up a default route */
 static int proxy_arp_set[NUM_PPP];     /* Have created proxy arp entry */
+#ifdef DNS_CONFIGURE
+static ns_t ns;                                /* local storage for NS config 
*/
+#endif
 
 /*
  * Callbacks for fsm code.  (CI = Configuration Information)
@@ -154,7 +161,162 @@
     return b;
 }
 
+/*
+ * loadDNS - load info from existing resolv.conf
+ * Adopted from ppp.
+ */
+static void
+loadDNS(ns)
+ns_t *ns;
+{
+    int fd;
+
+    ns->dns[0].s_addr = ns->dns[1].s_addr = INADDR_NONE;
+
+    if (ns->resolv != NULL) {
+       free(ns->resolv);
+       ns->resolv = NULL;
+    }
+  
+    if (ns->resolv_nons != NULL) {
+       free(ns->resolv_nons);
+       ns->resolv_nons = NULL;
+    }  
+    
+    if ((fd = open(_PATH_RESCONF, O_RDONLY)) != -1) {
+       struct stat st;
 
+       if (fstat(fd, &st) == 0) {
+           ssize_t got;
+
+           if ((ns->resolv_nons = (char *)malloc(st.st_size + 1)) == NULL)
+               IPCPDEBUG((LOG_ERROR, "Failed to malloc %lu for %s: %s\n",
+                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno)));
+           else if ((ns->resolv = (char *)malloc(st.st_size + 1)) == NULL) {
+               IPCPDEBUG((LOG_ERROR, "Failed(2) to malloc %lu for %s: %s\n",
+                   (unsigned long)st.st_size, _PATH_RESCONF, strerror(errno)));
+           free(ns->resolv_nons);
+           ns->resolv_nons = NULL;
+       } else if ((got = read(fd, ns->resolv, st.st_size)) != st.st_size) {
+           if (got == -1)
+               IPCPDEBUG((LOG_ERROR, "Failed to read %s: %s\n",
+                   _PATH_RESCONF, strerror(errno)));
+           else
+               IPCPDEBUG((LOG_ERROR, "Failed to read %s, got %lu not %lu\n",
+                   _PATH_RESCONF, (unsigned long)got, (unsigned 
long)st.st_size));
+           free(ns->resolv_nons);
+           ns->resolv_nons = NULL;
+           free(ns->resolv);
+           ns->resolv = NULL;
+       } else {
+
+#define issep(ch) ((ch) == ' ' || (ch) == '\t')
+#define isip(ch) (((ch) >= '0' && (ch) <= '9') || (ch) == '.')
+       
+           char *cp, *cp_nons, *ncp, ch;
+           int n;
+           
+           ns->resolv[st.st_size] = '\0';
+           
+           cp_nons = ns->resolv_nons;
+           cp = ns->resolv;
+           n = 0;
+           
+           while ((ncp = strstr(cp, "nameserver")) != NULL) {
+               if (ncp != cp) {
+                   memcpy(cp_nons, cp, ncp - cp);
+                   cp_nons += ncp - cp;
+               }
+               if ((ncp != cp && ncp[-1] != '\n') || !issep(ncp[10])) {
+                   memcpy(cp_nons, ncp, 9);
+                   cp_nons += 9;
+                   cp = ncp + 9;       /* Can't match "nameserver" at cp... */
+                   continue;
+               }
+
+               for (cp = ncp + 11; issep(*cp); cp++)   /* Skip whitespace */
+                   ;
+
+               for (ncp = cp; isip(*ncp); ncp++)       /* Jump over IP */
+                   ;
+                   
+               ch = *ncp;
+               *ncp = '\0';
+               if (n < 2 && inet_aton(cp, ns->dns))
+                   n++;
+               *ncp = ch;
+               
+               if ((cp = strchr(ncp, '\n')) == NULL)   /* Point at next line */
+                   cp = ncp + strlen(ncp);
+               else
+                   cp++;
+           }       
+           strcpy(cp_nons, cp);        /* Copy the end - including the NUL */
+           cp_nons += strlen(cp_nons) - 1;
+           while (cp_nons >= ns->resolv_nons && *cp_nons == '\n')
+               *cp_nons-- = '\0';
+           if (n == 2 && ns->dns[0].s_addr == INADDR_ANY) {
+               ns->dns[0].s_addr = ns->dns[1].s_addr;
+               ns->dns[1].s_addr = INADDR_ANY;
+           }
+       }
+    } else
+       IPCPDEBUG((LOG_ERROR, "Failed to stat opened %s: %s\n",
+           _PATH_RESCONF, strerror(errno)));
+       close(fd);
+  }               
+}
+
+/*
+ * writeDNS - update nameserver entries in resolv.conf
+ * Adopted from ppp.
+ */
+static int
+writeDNS(ns)
+ns_t *ns;
+{
+    char *paddr;
+    mode_t mask;
+    FILE *fp;
+  
+    if (ns->dns[0].s_addr == INADDR_ANY &&
+       ns->dns[1].s_addr == INADDR_ANY) {
+       IPCPDEBUG((LOG_INFO, "%s not modified: All nameservers NAKd\n",
+           _PATH_RESCONF));
+       return 0;
+    }
+    
+    if (ns->dns[0].s_addr == INADDR_ANY) {
+       ns->dns[0].s_addr = ns->dns[1].s_addr;
+       ns->dns[1].s_addr = INADDR_ANY;
+    }
+
+    mask = umask(022);
+    if ((fp = fopen(_PATH_RESCONF, "w")) != NULL) {
+       umask(mask);
+       if (ns->resolv_nons)
+           fputs(ns->resolv_nons, fp);
+       paddr = inet_ntoa(ns->dns[0]);
+       IPCPDEBUG((LOG_INFO, "Primary nameserver set to %s\n", paddr));
+       fprintf(fp, "\nnameserver %s\n", paddr);
+       if (ns->dns[1].s_addr != INADDR_ANY &&
+           ns->dns[1].s_addr != INADDR_NONE &&
+           ns->dns[1].s_addr != ns->dns[0].s_addr) {
+           paddr = inet_ntoa(ns->dns[1]);
+           IPCPDEBUG((LOG_INFO, "Secondary nameserver set to %s\n", paddr));
+           fprintf(fp, "nameserver %s\n", paddr);
+       }
+       if (fclose(fp) == EOF) {
+           IPCPDEBUG((LOG_INFO, "write(): Failed updating %s: %s\n",
+               _PATH_RESCONF, strerror(errno)));
+           return 0;
+       }
+    } else
+       umask(mask);
+
+    return 1;
+}
+  
 /*
  * ipcp_init - Initialize IPCP.
  */
@@ -180,6 +342,18 @@
     wo->maxslotindex = MAX_STATES - 1; /* really max index */
     wo->cflag = 1;
 
+#ifdef NS_NEGOTIATE
+    wo->neg_dns1 = 1;
+    wo->neg_wins1 = 1;
+    wo->neg_dns2 = 1;
+    wo->neg_wins2 = 1;
+#endif
+#ifdef DNS_CONFIGURE
+    ns.resolv = NULL;
+    ns.resolv_nons = NULL;
+    loadDNS(&ns);
+#endif
+
     /* max slots and slot-id compression are currently hardwired in */
     /* ppp_if.c to 16 and 1, this needs to be changed (among other */
     /* things) gmc */
@@ -298,6 +472,7 @@
     ipcp_options *go = &ipcp_gotoptions[f->unit];
     ipcp_options *wo = &ipcp_wantoptions[f->unit];
     ipcp_options *ho = &ipcp_hisoptions[f->unit];
+    int len;
 
 #define LENCIVJ(neg, old)      (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)
 #define LENCIADDR(neg, old)    (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)
@@ -326,8 +501,17 @@
        }
     }
 
-    return (LENCIADDR(go->neg_addr, go->old_addrs) +
+    len = (LENCIADDR(go->neg_addr, go->old_addrs) +
            LENCIVJ(go->neg_vj, go->old_vj));
+
+#ifdef NS_NEGOTIATE
+    len += LENCIADDR(go->neg_dns1, 0) +
+           LENCIADDR(go->neg_wins1, 0) +
+           LENCIADDR(go->neg_dns2, 0) +
+           LENCIADDR(go->neg_wins2, 0);
+#endif
+
+    return (len);
 }
 
 
@@ -383,6 +567,13 @@
     ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
            go->maxslotindex, go->cflag);
 
+#ifdef NS_NEGOTIATE
+    ADDCIADDR(CI_MS_DNS1, go->neg_dns1, 0, go->dnsaddr[0], 0);
+    ADDCIADDR(CI_MS_WINS1, go->neg_wins1, 0, go->winsaddr[0], 0);
+    ADDCIADDR(CI_MS_DNS2, go->neg_dns2, 0, go->dnsaddr[1], 0);
+    ADDCIADDR(CI_MS_WINS2, go->neg_wins2, 0, go->winsaddr[1], 0);
+#endif
+
     *lenp -= len;
 }
 
@@ -463,6 +654,13 @@
     ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,
            go->maxslotindex, go->cflag);
 
+#ifdef NS_NEGOTIATE
+    ACKCIADDR(CI_MS_DNS1, go->neg_dns1, 0, go->dnsaddr[0], 0);
+    ACKCIADDR(CI_MS_WINS1, go->neg_wins1, 0, go->winsaddr[0], 0);
+    ACKCIADDR(CI_MS_DNS2, go->neg_dns2, 0, go->dnsaddr[1], 0);
+    ACKCIADDR(CI_MS_WINS2, go->neg_wins2, 0, go->winsaddr[1], 0);
+#endif
+
     /*
      * If there are any remaining CIs, then this packet is bad.
      */
@@ -584,6 +782,25 @@
            );
 
     /*
+     * Accept the peer's idea of the DNS and WINS addresses
+     */
+#ifdef NS_NEGOTIATE
+    NAKCIADDR(CI_MS_DNS1, neg_dns1, 0, try.dnsaddr[0] = ciaddr1;);
+    NAKCIADDR(CI_MS_WINS1, neg_wins1, 0, try.winsaddr[0] = ciaddr1;);
+    NAKCIADDR(CI_MS_DNS2, neg_dns2, 0, try.dnsaddr[1] = ciaddr1;);
+    NAKCIADDR(CI_MS_WINS2, neg_wins2, 0, try.winsaddr[1] = ciaddr1;);
+#endif
+#ifdef DNS_CONFIGURE
+    /* update DNS info storage if needed */
+    if (try.dnsaddr[0] != 0) {
+       ns.dns[0].s_addr = try.dnsaddr[0];
+    }
+    if (try.dnsaddr[1] != 0) {
+        ns.dns[1].s_addr = try.dnsaddr[1];
+    }
+#endif
+
+    /*
      * There may be remaining CIs, if the peer is requesting negotiation
      * on an option that we didn't include in our request packet.
      * If they want to negotiate about IP addresses, we comply.
@@ -667,6 +884,9 @@
     u_short cishort;
     u_int32_t cilong;
     ipcp_options try;          /* options to request next time */
+#ifdef NS_NEGOTIATE
+    u_char citype, *next;
+#endif
 
     try = *go;
     /*
@@ -726,6 +946,35 @@
            go->maxslotindex, go->cflag);
 
     /*
+     * There may be remaining CIs, if the peer is unable to support
+     * DNS or WINS negotiation. If so, turn them off.
+     */
+#ifdef NS_NEGOTIATE
+    while (len > CILEN_VOID) {
+       GETCHAR(citype, p);
+       GETCHAR(cilen, p);
+       if( (len -= cilen) < 0 )
+           goto bad;
+       next = p + cilen - 2;
+       switch (citype) {
+       case CI_MS_DNS1:
+           try.neg_dns1 = 0;
+           break;
+       case CI_MS_WINS1:
+           try.neg_wins1 = 0;
+           break;
+       case CI_MS_DNS2:
+           try.neg_dns2 = 0;
+           break;
+       case CI_MS_WINS2:
+           try.neg_wins2 = 0;
+           break;
+       }
+       p = next;
+    }
+#endif
+    
+    /*
      * If there are any remaining CIs, then this packet is bad.
      */
     if (len != 0)
@@ -1173,6 +1422,9 @@
     /* set tcp compression */
     sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);
 
+    /* configure DNS */
+    writeDNS(&ns);
+
     /*
      * If we are doing dial-on-demand, the interface is already
      * configured, so we put out any saved-up packets, then set the
Index: pppd/ipcp.h
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/ipcp.h,v
retrieving revision 1.10
diff -u -r1.10 ipcp.h
--- pppd/ipcp.h 28 Aug 1999 01:19:03 -0000      1.10
+++ pppd/ipcp.h 25 Dec 2005 16:45:47 -0000
@@ -52,6 +52,12 @@
     int old_vj : 1;            /* use old (short) form of VJ option? */
     int accept_local : 1;      /* accept peer's value for ouraddr */
     int accept_remote : 1;     /* accept peer's value for hisaddr */
+#ifdef NS_NEGOTIATE
+    int neg_dns1 : 1;          /* Negotiate primary domain name server */
+    int neg_wins1 : 1;         /* Negotiate primary WINS */
+    int neg_dns2 : 1;          /* Negotiate secondary domain name server */
+    int neg_wins2 : 1;         /* Negotiate secondary WINS */
+#endif
     u_short vj_protocol;       /* protocol value to use in VJ option */
     u_char maxslotindex, cflag;        /* values for RFC1332 VJ compression 
neg. */
     u_int32_t ouraddr, hisaddr;        /* Addresses in NETWORK BYTE ORDER */
@@ -59,6 +65,14 @@
     u_int32_t winsaddr[2];     /* Primary and secondary MS WINS entries */
 } ipcp_options;
 
+#ifdef DNS_CONFIGURE
+typedef struct ns {
+    struct in_addr dns[2];     /* Current DNS addresses */
+    char *resolv;              /* Contents of resolv.conf */
+    char *resolv_nons;         /* Contents of resolv.conf without ns */
+} ns_t;
+#endif
+
 extern fsm ipcp_fsm[];
 extern ipcp_options ipcp_wantoptions[];
 extern ipcp_options ipcp_gotoptions[];
Index: pppd/main.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/pppd/main.c,v
retrieving revision 1.19.2.1
diff -u -r1.19.2.1 main.c
--- pppd/main.c 30 Jul 2002 03:50:40 -0000      1.19.2.1
+++ pppd/main.c 25 Dec 2005 14:36:29 -0000
@@ -33,6 +33,7 @@
 #include <netdb.h>
 #include <utmp.h>
 #include <pwd.h>
+#include <netinet/in.h>
 #include <sys/param.h>
 #include <sys/types.h>
 #include <sys/wait.h>
_______________________________________________
freebsd-hackers@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-hackers
To unsubscribe, send any mail to "[EMAIL PROTECTED]"

Reply via email to