[PATCH] pppd: added auto DNS configuration
Igor Pokrovsky
ip at doom.homeunix.org
Tue Dec 27 08:52:19 PST 2005
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.
-------------- next part --------------
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>
More information about the freebsd-hackers
mailing list