1/*	$Id: resolv_token.l,v 1.1.1.1 2006/12/04 00:45:33 Exp $	*/
2
3/*
4 * Copyright (C) International Business Machines  Corp., 2003
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 */
30
31%option noyywrap
32
33%{
34#include <stdio.h>
35#include <string.h>
36#include <sys/types.h>
37#include <sys/file.h>
38#include <sys/stat.h>
39#include <unistd.h>
40
41#include <netinet/in.h>
42#include <arpa/inet.h>
43
44#include <errno.h>
45#include <syslog.h>
46#include <string.h>
47
48#include "queue.h"
49#include "dhcp6.h"
50#include "config.h"
51#include "common.h"
52
53#undef yywrap
54
55#define YYABORT(msg) dprintf(LOG_ERR, msg " %s lineno %d.", \
56	yytext, num_lines)
57
58#define ABORT   do {    \
59	YYABORT("resolv parse error");   \
60	remove(RESOLV_CONF_DHCPV6_FILE); \
61	exit(1);        \
62} while (0)
63
64
65extern struct dhcp6_if *dhcp6_if;
66static int num_lines = 0;
67static struct dns_list *new_dns_list;
68static FILE *dhcp6_resolv_file;
69static int oldfd, newfd;
70
71static int yywrap __P(());
72int resolv_parse __P((struct dns_list *));
73static int update_resolver __P((struct dns_list *));
74
75%}
76
77digit           [0-9]
78number          ({digit})+
79hexdigit        ([a-f]|[A-F]|[0-9])
80ipv4addr        ({digit}{1,3}"."{digit}{1,3}"."{digit}{1,3}"."{digit}{1,3})
81addr_head       ("::"|{hexdigit}{1,4}(":"|"::"))
82addr_tail       ({hexdigit}{1,4}|({hexdigit}{1,4}"::")|{ipv4addr})?
83addr_body       ({hexdigit}{1,4}(":"|"::"))*
84ipv6addr        {addr_head}{addr_body}{addr_tail}
85whitespace      ([ \t])+
86domainname	[a-zA-Z0-9:\._-]+
87nl              \n
88
89
90%s S_ADDR S_DOMAIN
91
92%%
93
94{nl}            {fprintf(dhcp6_resolv_file, yytext);
95		num_lines++;}
96{whitespace}    {fprintf(dhcp6_resolv_file, yytext);}
97
98"nameserver"	{fprintf(dhcp6_resolv_file, yytext);
99		BEGIN S_ADDR;}
100"search"	{fprintf(dhcp6_resolv_file, yytext);
101		BEGIN S_DOMAIN;}
102
103<S_DOMAIN>{domainname} { struct domain_list *domainname, *temp;
104		domainname = (struct domain_list *)malloc(sizeof(*domainname));
105		if (domainname == NULL)
106			ABORT;
107		if (strlen(yytext) > MAXDNAME)
108			ABORT;
109		fprintf(dhcp6_resolv_file, yytext);
110		strcpy(domainname->name, yytext);
111		dprintf(LOG_DEBUG, "parse domain name %s", domainname->name);
112		domainname->next = NULL;
113		if (dhcp6_if->dnslist.domainlist == NULL)
114			dhcp6_if->dnslist.domainlist = domainname;
115		else {
116			for (temp = dhcp6_if->dnslist.domainlist; temp; temp = temp->next) {
117				if (temp->next == NULL) {
118					temp->next = domainname;
119					break;
120				}
121			}
122		}
123		BEGIN S_DOMAIN;}
124
125<S_DOMAIN>. {fprintf(dhcp6_resolv_file, yytext); BEGIN INITIAL;}
126
127<S_ADDR>{ipv6addr} {struct in6_addr addr;
128		fprintf(dhcp6_resolv_file, yytext);
129		if (inet_pton(AF_INET6, yytext, &addr) < 1)
130			ABORT;
131		dprintf(LOG_DEBUG, "parse name server %s", in6addr2str(&addr, 0));
132		if (dhcp6_add_listval(&dhcp6_if->dnslist.addrlist,
133		    &addr, DHCP6_LISTVAL_ADDR6) == NULL) {
134			dprintf(LOG_ERR, "%s" "failed to add a DNS server", FNAME);
135			ABORT;
136		}
137		BEGIN S_ADDR;}
138<S_ADDR>. {fprintf(dhcp6_resolv_file, yytext); BEGIN INITIAL;}
139.	{fprintf(dhcp6_resolv_file, yytext);}
140
141%%
142
143/* parse resolv.conf
144 * create a new resolv.conf.dhcpv6
145 * mv /etc/resolv.conf to /etc/resolv.conf.V6BAK
146 * link resolv.conf to resolv.conf.dhcpv6
147 */
148int
149resolv_parse(struct dns_list *dnslist)
150{
151	struct stat buf;
152	char pidstr[128];
153	sprintf(pidstr, "%d", getpid());
154	strcpy(resolv_dhcpv6_file, RESOLV_CONF_DHCPV6_FILE);
155	strcat(resolv_dhcpv6_file, pidstr);
156	TAILQ_INIT(&dhcp6_if->dnslist.addrlist);
157	dhcp6_if->dnslist.domainlist = NULL;
158	new_dns_list = dnslist;
159	while ((oldfd = open(RESOLV_CONF_FILE, O_EXCL)) < 0) {
160		switch (errno) {
161		case ENOENT:
162			/* exclusive open of new resolv.conf.dhcpv6 file */
163			if ((newfd = open(resolv_dhcpv6_file,
164			    O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0644))
165			    < 0) {
166				dprintf(LOG_ERR, "%s"
167					" failed to open resolv.conf.dhcpv6 file", FNAME);
168				return (-1);
169			}
170			if ((dhcp6_resolv_file = fdopen(newfd, "w")) == NULL) {
171				dprintf(LOG_ERR, "%s"
172					" failed to fdopen resolv.conf.dhcpv6 file", FNAME);
173				return (-1);
174			}
175			return(update_resolver(dnslist));
176		case EACCES:
177			sleep(1);
178			continue;
179		default:
180			dprintf(LOG_ERR, "resolv_parse: fopen(%s): %s",
181				RESOLV_CONF_FILE, strerror(errno));
182			return (-1);
183		}
184	}
185	if (lstat(RESOLV_CONF_FILE, &buf)) {
186		dprintf(LOG_ERR, "lstat resolv.conf file failed");
187		return (-1);
188	}
189	if ((yyin = fdopen(oldfd, "r")) == NULL) {
190		dprintf(LOG_ERR, "resolv_parse: fdopen(%s): %s",
191			RESOLV_CONF_FILE, strerror(errno));
192		return (-1);
193	}
194	/* exclusive open of new resolv.conf.dhcpv6 file */
195	if ((newfd = open(resolv_dhcpv6_file,
196	    O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, buf.st_mode)) < 0) {
197		dprintf(LOG_ERR, "%s"
198			" failed to open resolv.conf.dhcpv6 file", FNAME);
199		return (-1);
200	}
201	if ((dhcp6_resolv_file = fdopen(newfd, "w")) == NULL) {
202		dprintf(LOG_ERR, "%s"
203			" failed to fdopen resolv.conf.dhcpv6 file", FNAME);
204		return (-1);
205	}
206	yylex();
207	return 0;
208}
209
210static int
211update_resolver(struct dns_list *dns_list)
212{
213	struct domain_list *oldlist, *dprev, *dlist, *dlist_next;
214	struct dhcp6_listval *d, *d_next;
215	struct stat buf;
216	int i = 0;
217	fseek(dhcp6_resolv_file, 0, SEEK_CUR);
218	if (!TAILQ_EMPTY(&dns_list->addrlist)) {
219		for (d = TAILQ_FIRST(&dns_list->addrlist); d; d = d_next, i++) {
220			struct dhcp6_listval *lv;
221			dprintf(LOG_DEBUG, "%s" " received nameserver[%d] %s",
222				FNAME, i, in6addr2str(&d->val_addr6, 0));
223			d_next = TAILQ_NEXT(d, link);
224			for (lv = TAILQ_FIRST(&dhcp6_if->dnslist.addrlist); lv;
225			     lv = TAILQ_NEXT(lv, link)) {
226				if (IN6_ARE_ADDR_EQUAL(&lv->val_addr6, &d->val_addr6)) {
227					dprintf(LOG_DEBUG, "%s"
228						"nameserver %s found in resolv.conf",
229						FNAME, in6addr2str(&d->val_addr6, 0));
230					TAILQ_REMOVE(&dns_list->addrlist, d, link);
231					continue;
232				}
233			}
234		}
235		if (!TAILQ_EMPTY(&dns_list->addrlist)) {
236			fprintf(dhcp6_resolv_file, "nameserver ");
237			for (d = TAILQ_FIRST(&dns_list->addrlist); d;
238				d = d_next, i++) {
239				d_next = TAILQ_NEXT(d, link);
240				fprintf(dhcp6_resolv_file, "%s",
241					in6addr2str(&d->val_addr6, 0));
242				if (d_next != NULL)
243					fprintf(dhcp6_resolv_file, " ");
244				else
245					fprintf(dhcp6_resolv_file, "\n");
246			}
247		}
248	}
249
250	if (dns_list->domainlist != NULL) {
251		i = 0;
252		for (dlist = dns_list->domainlist, dprev = dns_list->domainlist;
253		     dlist; i++, dlist = dlist_next) {
254			int found = 0;
255			dprintf(LOG_DEBUG, "%s" " received domainname[%d] %s",
256				FNAME, i, dlist->name);
257			if (dhcp6_if->dnslist.domainlist == NULL)
258				break;
259			for (oldlist = dhcp6_if->dnslist.domainlist; oldlist;
260			     oldlist = oldlist->next) {
261				if (strcmp(oldlist->name, dlist->name) == 0) {
262					found = 1;
263					dprintf(LOG_DEBUG, "%s" "domain name %s found in "
264						"resolv.conf", FNAME, dlist->name);
265					if (dprev == dlist) {
266						dprev = dlist->next;
267						dns_list->domainlist = dlist->next;
268					} else
269						dprev->next = dlist->next;
270					break;
271				}
272			}
273			dlist_next = dlist->next;
274			if (found == 0)
275				dprev = dlist;
276			else {
277				free(dlist);
278			}
279		}
280		if (dns_list->domainlist != NULL) {
281			fprintf(dhcp6_resolv_file, "search ");
282			for (dlist = dns_list->domainlist; dlist; dlist = dlist->next) {
283				dprintf(LOG_DEBUG, "%s" "domain name %s added in resolv.conf",
284					FNAME, dlist->name);
285				fprintf(dhcp6_resolv_file, "%s", dlist->name);
286				if (dlist->next != NULL)
287					fprintf(dhcp6_resolv_file, " ");
288				else
289					fprintf(dhcp6_resolv_file, "\n");
290			}
291		}
292	}
293	if (fflush(dhcp6_resolv_file) == EOF) {
294		dprintf(LOG_ERR, "%s" "write resolv.conf.dhcpv6 file fflush failed %s",
295			FNAME, strerror(errno));
296		return (-1);
297	}
298	if (fsync(newfd) < 0) {
299		dprintf(LOG_ERR, "%s" "write resolv.conf.dhcpv6 file failed %s",
300			FNAME, strerror(errno));
301		return (-1);
302	}
303	fclose(dhcp6_resolv_file);
304	close(newfd);
305	if (!lstat(RESOLV_CONF_FILE, &buf)) {
306		if ((lstat(RESOLV_CONF_BAK_FILE, &buf) < 0) && (errno == ENOENT)) {
307			if (link(RESOLV_CONF_FILE, RESOLV_CONF_BAK_FILE)) {
308				dprintf(LOG_ERR, "%s"
309					" backup failed for resolv.conf file", FNAME);
310				return (-1);
311			}
312		}
313	}
314	if (rename(resolv_dhcpv6_file, RESOLV_CONF_FILE)) {
315		dprintf(LOG_ERR, "%s" " rename failed for resolv.conf file", FNAME);
316		return(-1);
317	}
318
319    /* Foxconn added start pling 09/30/2009 */
320    /* Signal dnsmasq to reload resolv.conf */
321    system("killall -SIGHUP dnsmasq");
322    /* Foxconn added end pling 09/30/2009 */
323
324	return (0);
325}
326
327static int
328yywrap()
329{
330	update_resolver(new_dns_list);
331	fclose(yyin);
332	close(oldfd);
333}
334