From owner-freebsd-hackers@FreeBSD.ORG Tue Dec 27 16:52:19 2005 Return-Path: X-Original-To: hackers@freebsd.org Delivered-To: freebsd-hackers@FreeBSD.ORG Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id F299416A41F for ; Tue, 27 Dec 2005 16:52:18 +0000 (GMT) (envelope-from igor@doom.homeunix.org) Received: from mail.ecolines.ru (ns.ecolines.ru [81.3.181.213]) by mx1.FreeBSD.org (Postfix) with ESMTP id 9624243D46 for ; Tue, 27 Dec 2005 16:52:05 +0000 (GMT) (envelope-from igor@doom.homeunix.org) Received: (qmail 29526 invoked from network); 27 Dec 2005 16:55:56 -0000 Received: from unknown (HELO doom.homeunix.org) (ip@212.113.114.55) by mail.ecolines.ru with ESMTPA; 27 Dec 2005 16:55:56 -0000 Received: from doom.homeunix.org (localhost [127.0.0.1]) by doom.homeunix.org (8.13.4/8.13.4) with ESMTP id jBRGmnoU010494; Tue, 27 Dec 2005 19:50:09 +0300 (MSK) (envelope-from igor@doom.homeunix.org) Received: (from igor@localhost) by doom.homeunix.org (8.13.4/8.13.4/Submit) id jBRGmdHx010493; Tue, 27 Dec 2005 19:48:39 +0300 (MSK) (envelope-from igor) Date: Tue, 27 Dec 2005 19:48:39 +0300 From: Igor Pokrovsky To: hackers@freebsd.org Message-ID: <20051227164839.GA10394@doom.homeunix.org> Mail-Followup-To: hackers@freebsd.org, peter@freebsd.org, mistic@ecolines.ru Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="LQksG6bCIzRHxTLp" Content-Disposition: inline User-Agent: Mutt/1.4.2.1i Cc: mistic@ecolines.ru, peter@freebsd.org Subject: [PATCH] pppd: added auto DNS configuration X-BeenThere: freebsd-hackers@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: Technical Discussions relating to FreeBSD List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 27 Dec 2005 16:52:19 -0000 --LQksG6bCIzRHxTLp Content-Type: text/plain; charset=us-ascii Content-Disposition: inline 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. --LQksG6bCIzRHxTLp Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="pppd.diff" 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 #include #include +#include #include #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 #include #include +#include #include #include #include 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 #include #include +#include #include #include +#include #include #include #include +#include +#include #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 #include #include +#include #include #include #include --LQksG6bCIzRHxTLp--