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