1/* $Id: lease_token.l,v 1.1.1.1 2006/12/04 00:45:31 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 * SUCH DAMAGE. 30 */ 31 32/* Author: Shirley Ma, xma@us.ibm.com */ 33 34%option noyywrap 35 36%{ 37 38#include <stdio.h> 39#include <string.h> 40#include <sys/types.h> 41#include <sys/time.h> 42#include <sys/timeb.h> 43#include <syslog.h> 44#include <errno.h> 45#include <sys/socket.h> 46#include <arpa/inet.h> 47 48#include <net/if.h> 49#include <linux/sockios.h> 50#include "queue.h" 51#include "dhcp6.h" 52#include "config.h" 53#include "common.h" 54#include "lease.h" 55#include "hash.h" 56#include "timer.h" 57 58#define LEASE_ADDR_FLAG 0x01 59#define LEASE_DUID_FLAG 0x02 60#define LEASE_IAID_FLAG 0x04 61#define LEASE_SDATE_FLAG 0x08 62 63#define LEASE_VTIME_FLAG 0x10 64#define LEASE_PTIME_FLAG 0x20 65#define LEASE_RNTIME_FLAG 0x40 66#define LEASE_RBTIME_FLAG 0x80 67 68#define LEASE_HNAME_FLAG 0x100 69#define LEASE_LL_FLAG 0x200 70 71#define VALID_LEASE_FLAG(a) \ 72 ((a & LEASE_ADDR_FLAG) && (a & LEASE_SDATE_FLAG) && \ 73 (a & LEASE_VTIME_FLAG) && (a & LEASE_PTIME_FLAG) && \ 74 (a & LEASE_IAID_FLAG) && (a & LEASE_RNTIME_FLAG) && \ 75 (a & LEASE_RBTIME_FLAG) && (a & LEASE_DUID_FLAG)) 76 77#define YYABORT(msg) dprintf(LOG_ERR, msg " %s lineno %d.", \ 78 yytext, num_lines) 79 80#define ABORT do { \ 81 YYABORT("lease parse error"); \ 82 exit(1); \ 83} while (0) 84 85extern struct dhcp6_timer *dhcp6_lease_timo __P((void *)); 86extern struct dhcp6_iaidaddr client6_iaidaddr; 87 88static int num_lines = 1; 89static struct dhcp6_lease *lease_rec; 90static struct client6_if client6_info; 91 92static u_int16_t lease_flags = 0; 93 94static int add_lease __P((struct dhcp6_iaidaddr *, struct dhcp6_lease *)); 95static int remove_lease __P((struct dhcp6_lease *)); 96 97%} 98 99digit [0-9] 100number ({digit})+ 101decimal ({number}"."{number}) 102hexdigit ([a-f]|[A-F]|[0-9]) 103hexpair ({hexdigit}{hexdigit}) 104ipv4addr ({digit}{1,3}"."{digit}{1,3}"."{digit}{1,3}"."{digit}{1,3}) 105addr_head ("::"|{hexdigit}{1,4}(":"|"::")) 106addr_tail ({hexdigit}{1,4}|({hexdigit}{1,4}"::")|{ipv4addr})? 107addr_body ({hexdigit}{1,4}(":"|"::"))* 108ipv6addr {addr_head}{addr_body}{addr_tail} 109duid_id {hexpair}(:{hexpair})* 110whitespace ([ \t])+ 111string [a-zA-Z]([a-zA-Z]|{digit})*(":"{digit}+)? 112lbrace \{ 113rbrace \} 114slash \/ 115colon \: 116semi \; 117nl \n 118comment \#.* 119 120%s S_LEASE 121%s S_PLEN 122%s S_HNAME 123%s S_LL 124%s S_DUID 125%s S_SDUID 126%s S_IAID 127%s S_IATYPE 128%s S_RNTIME 129%s S_RBTIME 130%s S_PTIME 131%s S_VTIME 132%s S_DATE 133%s S_STATE 134%s S_IGNORE 135 136%% 137 138{comment} {;/* ignore comments */} 139{nl} {num_lines++; BEGIN INITIAL;} 140{whitespace} {;} 141{semi} {;} 142 /* lease parser */ 143"lease" { 144 lease_rec = (struct dhcp6_lease *)malloc(sizeof(*lease_rec)); 145 if (lease_rec == NULL) { 146 YYABORT("failed to allocate memory for a lease"); 147 ABORT; 148 } 149 memset(lease_rec, 0, sizeof(*lease_rec)); 150 memset(&client6_info, 0, sizeof(client6_info)); 151 lease_flags = 0; 152 BEGIN S_LEASE;} 153"hostname:" {BEGIN S_HNAME;} 154"linklocal:" {BEGIN S_LL;} 155"DUID:" {BEGIN S_DUID;} 156"SDUID:" {BEGIN S_SDUID;} 157"IAID:" {BEGIN S_IAID;} 158"RenewTime:" {BEGIN S_RNTIME;} 159"RebindTime:" {BEGIN S_RBTIME;} 160"ValidLifeTime:" {BEGIN S_VTIME;} 161"PreferredLifeTime:" {BEGIN S_PTIME;} 162"start date:" {BEGIN S_DATE;} 163"(start_date" {BEGIN S_IGNORE;} 164"state:" {BEGIN S_STATE;} 165{rbrace} {if (do_iaidaddr_hash(lease_rec, &client6_info) != 0) { 166 ABORT; 167 } 168 else { 169 BEGIN INITIAL; 170 } 171} 172<S_LEASE>{ipv6addr} { 173 struct in6_addr addr; 174 if(inet_pton(AF_INET6, yytext, &addr) < 1) { 175 YYABORT("invalid address"); 176 free(lease_rec); 177 ABORT; 178 } 179 memcpy(&lease_rec->lease_addr.addr, &addr, 180 sizeof(lease_rec->lease_addr.addr)); 181 lease_flags |= LEASE_ADDR_FLAG;} 182<S_LEASE>{slash} {BEGIN S_PLEN;} 183<S_LEASE>. {ABORT;} 184<S_PLEN>{number} {lease_rec->lease_addr.plen = (u_int8_t)atoi(yytext);} 185<S_PLEN>{lbrace} {;} 186<S_PLEN>. {ABORT;} 187<S_HNAME>{string} {strncpy(lease_rec->hostname, yytext, sizeof(yytext)); 188 lease_flags |= LEASE_HNAME_FLAG;} 189<S_HNAME>. {ABORT;} 190<S_LL>{ipv6addr} { 191 struct in6_addr addr; 192 if(inet_pton(AF_INET6, yytext, &addr) < 1) { 193 YYABORT("invalid address"); 194 free(lease_rec); 195 ABORT; 196 } 197 memcpy(&lease_rec->linklocal, &addr, 198 sizeof(lease_rec->linklocal)); 199 lease_flags |= LEASE_LL_FLAG;} 200<S_LL>. {ABORT;} 201<S_DUID>{duid_id} {configure_duid(yytext, &client6_info.clientid); 202 lease_flags |= LEASE_DUID_FLAG;} 203<S_DUID>. {ABORT;} 204<S_SDUID>{duid_id} {configure_duid(yytext, &client6_info.serverid);} 205<S_SDUID>. {ABORT;} 206<S_IAID>{number} {client6_info.iaidinfo.iaid = strtoll(yytext, NULL, 10); 207 lease_flags |= LEASE_IAID_FLAG;} 208<S_IAID>"type:" {BEGIN S_IATYPE;} 209<S_IAID>. {ABORT;} 210<S_IATYPE>{number} {lease_rec->lease_addr.type = (u_int8_t)atoi(yytext); 211 client6_info.type = (u_int8_t)atoi(yytext);} 212<S_IATYPE>. {ABORT;} 213<S_RNTIME>{number} {client6_info.iaidinfo.renewtime = (u_int32_t)strtoul(yytext, NULL, 10); 214 lease_flags |= LEASE_RNTIME_FLAG;} 215<S_RNTIME>. {ABORT;} 216<S_RBTIME>{number} {client6_info.iaidinfo.rebindtime = (u_int32_t)strtoul(yytext, NULL, 10); 217 lease_flags |= LEASE_RBTIME_FLAG;} 218<S_RBTIME>. {ABORT;} 219<S_VTIME>{number} {lease_rec->lease_addr.validlifetime = (u_int32_t)strtoul(yytext, NULL, 10); 220 lease_flags |= LEASE_VTIME_FLAG;} 221<S_VTIME>. {ABORT;} 222<S_PTIME>{number} {lease_rec->lease_addr.preferlifetime = (u_int32_t)strtoul(yytext, NULL, 10); 223 lease_flags |= LEASE_PTIME_FLAG;} 224<S_PTIME>. {ABORT;} 225<S_DATE>{number} {lease_rec->start_date = (time_t)strtoul(yytext, NULL, 10); 226 lease_flags |= LEASE_SDATE_FLAG;} 227<S_DATE>. {ABORT;} 228<S_STATE>{number} {lease_rec->state = (state_t)atoi(yytext);} 229<S_STATE>. {ABORT;} 230<S_IGNORE>. {;} 231 232. {ABORT;} 233 234%% 235 236 237void 238lease_parse(file) 239 FILE *file; 240{ 241 242 fseek(file, 0, 0); 243 yyin = file; 244 yylex(); 245 return; 246} 247 248int 249do_iaidaddr_hash(lease_rec, key) 250 struct dhcp6_lease *lease_rec; 251 struct client6_if *key; 252{ 253 struct dhcp6_iaidaddr *iaidaddr; 254 struct dhcp6_lease *found_lease; 255 struct timeb now; 256 time_t offset; 257 struct timeval timo; 258 double d; 259 260 if (!VALID_LEASE_FLAG(lease_flags) || 261 (lease_rec->lease_addr.preferlifetime > lease_rec->lease_addr.validlifetime)) { 262 dprintf(LOG_ERR, "parse an invalid lease %s/%d within line %d", 263 in6addr2str(&lease_rec->lease_addr.addr, 0), 264 lease_rec->lease_addr.plen, num_lines); 265 return (-1); 266 } 267 ftime(&now); 268 offset = now.time - lease_rec->start_date; 269 dprintf(LOG_DEBUG, "now : %ld; offset: %ld ", now.time, offset); 270 if (offset > lease_rec->lease_addr.validlifetime) { 271 dprintf(LOG_INFO, "This lease addr %s/%d has been expired.", 272 in6addr2str(&lease_rec->lease_addr.addr, 0), 273 lease_rec->lease_addr.plen); 274 free(lease_rec); 275 return (0); 276 } 277 278 if (lease_rec->state == INVALID) { 279 dprintf(LOG_INFO, "This lease addr %s/%d is invalid. Removing.", 280 in6addr2str(&lease_rec->lease_addr.addr, 0), 281 lease_rec->lease_addr.plen); 282 found_lease = hash_search(lease_hash_table, &lease_rec->lease_addr); 283 /* remove the previous old lease */ 284 if(found_lease) { 285 remove_lease(found_lease); 286 } 287 free(lease_rec); 288 return (0); 289 } 290 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 291 if (add_lease(&client6_iaidaddr, lease_rec) != 0) 292 return (-1); 293 else { 294 memcpy(&client6_iaidaddr.client6_info, &client6_info, 295 sizeof(client6_iaidaddr.client6_info)); 296 dprintf(LOG_DEBUG, "hash add client iaidaddr type %d for " 297 " duid %s for iaid %u", 298 client6_iaidaddr.client6_info.type, 299 duidstr(&client6_iaidaddr.client6_info.clientid), 300 client6_iaidaddr.client6_info.iaidinfo.iaid); 301 return (0); 302 } 303 } 304 iaidaddr = (struct dhcp6_iaidaddr *)hash_search(server6_hash_table, key); 305 if (iaidaddr){ 306 if (iaidaddr->client6_info.iaidinfo.iaid != client6_info.iaidinfo.iaid || 307 duidcmp(&iaidaddr->client6_info.clientid, &client6_info.clientid)) { 308 dprintf(LOG_DEBUG, "%s" 309 "this client iaidinfo is different to others", FNAME); 310 return (-1); 311 } 312 found_lease = hash_search(lease_hash_table, &lease_rec->lease_addr); 313 /* remove the previous old lease */ 314 if(found_lease) { 315 if (found_lease->start_date < lease_rec->start_date) { 316 dprintf(LOG_DEBUG, "%s" "remove old lease %s/%d", FNAME, 317 in6addr2str(&lease_rec->lease_addr.addr, 0), 318 lease_rec->lease_addr.plen); 319 /* update the client6_info too */ 320 memcpy(&iaidaddr->client6_info, &client6_info, 321 sizeof(iaidaddr->client6_info)); 322 iaidaddr->start_date = lease_rec->start_date; 323 remove_lease(found_lease); 324 } else { 325 free(lease_rec); 326 return (0); 327 } 328 } 329 } else { 330 iaidaddr = (struct dhcp6_iaidaddr *)malloc(sizeof(*iaidaddr)); 331 if (!iaidaddr) { 332 dprintf(LOG_ERR, "%s" "failed to allocate memory", FNAME); 333 return (-1); 334 } 335 memset(iaidaddr, 0, sizeof(*iaidaddr)); 336 TAILQ_INIT(&iaidaddr->lease_list); 337 /* get the client info */ 338 memcpy(&iaidaddr->client6_info, &client6_info, sizeof(iaidaddr->client6_info)); 339 if (hash_add(server6_hash_table, 340 &iaidaddr->client6_info, iaidaddr) != 0) { 341 dprintf(LOG_ERR, "%s" "hash add failed", FNAME); 342 free(iaidaddr); 343 return (-1); 344 } 345 dprintf(LOG_DEBUG, "hash add client iaidaddr %u type %d for duid %s", 346 iaidaddr->client6_info.iaidinfo.iaid, 347 iaidaddr->client6_info.type, 348 duidstr(&iaidaddr->client6_info.clientid)); 349 } 350 if (add_lease(iaidaddr, lease_rec) != 0) 351 return (-1); 352 iaidaddr->state = ACTIVE; 353 iaidaddr->start_date = lease_rec->start_date; 354 d = get_max_validlifetime(iaidaddr) - offset; 355 timo.tv_sec = (long)d; 356 timo.tv_usec = 0; 357 /* update the start date and timer */ 358 if (!iaidaddr->timer && (iaidaddr->timer = 359 dhcp6_add_timer(dhcp6_iaidaddr_timo, iaidaddr)) == NULL) { 360 dprintf(LOG_ERR, "%s" "failed to add a timer for iaid %u", 361 FNAME, iaidaddr->client6_info.iaidinfo.iaid); 362 return (-1); 363 } 364 dhcp6_set_timer(&timo, iaidaddr->timer); 365 return (0); 366} 367 368static int 369add_lease(iaidaddr, lease) 370 struct dhcp6_iaidaddr *iaidaddr; 371 struct dhcp6_lease *lease; 372{ 373 struct timeval timo; 374 struct timeb now; 375 time_t offset; 376 struct dhcp6_lease *found_lease; 377 double d; 378 /* set up timer out for lease, iaidaddr timer out will be set up in 379 * post_conf_lease */ 380 ftime(&now); 381 offset = now.time - lease_rec->start_date; 382 if (dhcp6_mode == DHCP6_MODE_CLIENT) { 383 if ((found_lease = dhcp6_find_lease(iaidaddr, &lease_rec->lease_addr)) 384 != NULL) { 385 if (!(found_lease->start_date > lease_rec->start_date)) { 386 dprintf(LOG_DEBUG, "%s" "remove old lease %s/%d", FNAME, 387 in6addr2str(&lease_rec->lease_addr.addr, 0), 388 lease_rec->lease_addr.plen); 389 if (iaidaddr->client6_info.iaidinfo.iaid != 390 client6_info.iaidinfo.iaid) { 391 dprintf(LOG_DEBUG, "%s" 392 " this lease %s client iaidinfo is different" 393 " to the previous lease", 394 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0)); 395 return (-1); 396 } 397 iaidaddr->client6_info.iaidinfo.renewtime = 398 client6_info.iaidinfo.renewtime; 399 iaidaddr->client6_info.iaidinfo.rebindtime = 400 client6_info.iaidinfo.rebindtime; 401 iaidaddr->start_date = lease_rec->start_date; 402 remove_lease(found_lease); 403 } else { 404 free(lease_rec); 405 return (0); 406 } 407 } 408 /* if this is the first lease */ 409 if (TAILQ_EMPTY(&iaidaddr->lease_list)) { 410 if (iaidaddr->client6_info.iaidinfo.iaid != 411 client6_info.iaidinfo.iaid) { 412 dprintf(LOG_DEBUG, "%s" 413 " this lease %s client iaidinfo is different" 414 " to the previous lease", 415 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0)); 416 return (-1); 417 } 418 iaidaddr->client6_info.iaidinfo.renewtime = 419 client6_info.iaidinfo.renewtime; 420 iaidaddr->client6_info.iaidinfo.rebindtime = 421 client6_info.iaidinfo.rebindtime; 422 iaidaddr->start_date = lease_rec->start_date; 423 } 424 if (!memcmp(&iaidaddr->client6_info, &client6_info, 425 sizeof(iaidaddr->client6_info))) { 426 /* iaidaddr->start_date != lease_rec->start_date) */ 427 dprintf(LOG_DEBUG, "%s" " this lease %s client iaidinfo is different" 428 " to the previous lease", 429 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0)); 430 return (-1); 431 } 432 } 433 if (lease_rec->state == INVALID) { 434 dprintf(LOG_DEBUG, "parse an invalid state lease %s/%d in line %d", 435 in6addr2str(&lease_rec->lease_addr.addr, 0), 436 lease_rec->lease_addr.plen, num_lines); 437 free(lease_rec); 438 return (0); 439 } 440 if ((lease_rec->timer = dhcp6_add_timer(dhcp6_lease_timo, lease_rec)) == NULL) { 441 dprintf(LOG_ERR, "%s" " failed to create a timer for lease %s", 442 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0)); 443 return (-1); 444 } 445 if (lease_rec->lease_addr.preferlifetime > offset) { 446 lease_rec->state = ACTIVE; 447 d = lease_rec->lease_addr.preferlifetime - offset; 448 } else { 449 lease_rec->state = EXPIRED; 450 d = lease_rec->lease_addr.validlifetime - offset; 451 } 452 timo.tv_sec = (long)d; 453 timo.tv_usec = 0; 454 dhcp6_set_timer(&timo, lease_rec->timer); 455 if (dhcp6_mode == DHCP6_MODE_SERVER) { 456 if (hash_add(lease_hash_table, &lease_rec->lease_addr, lease_rec) != 0) { 457 dprintf(LOG_ERR, "%s" "hash add lease failed for %s", 458 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0)); 459 free(lease_rec); 460 return (-1); 461 } 462 } 463 lease_rec->iaidaddr = iaidaddr; 464 lease_rec->lease_addr.status_code = DH6OPT_STCODE_UNDEFINE; 465 TAILQ_INSERT_TAIL(&iaidaddr->lease_list, lease_rec, link); 466 dprintf(LOG_INFO, "%s" "add lease addr %s/%d type %d to %u", 467 FNAME, in6addr2str(&lease_rec->lease_addr.addr, 0), lease_rec->lease_addr.plen, 468 lease_rec->lease_addr.type, lease_rec->iaidaddr->client6_info.iaidinfo.iaid); 469 return (0); 470} 471 472static int 473remove_lease(lease) 474 struct dhcp6_lease *lease; 475{ 476 if (dhcp6_mode == DHCP6_MODE_SERVER) { 477 if (hash_delete(lease_hash_table, &lease->lease_addr) != 0) { 478 dprintf(LOG_ERR, "%s" "failed to remove an address %s from hash", 479 FNAME, in6addr2str(&lease->lease_addr.addr, 0)); 480 return (-1); 481 } 482 } 483 if (lease->timer) 484 dhcp6_remove_timer(lease->timer); 485 TAILQ_REMOVE(&lease->iaidaddr->lease_list, lease, link); 486 dprintf(LOG_INFO, "%s" "removed lease addr %s/%d from %u", 487 FNAME, in6addr2str(&lease->lease_addr.addr, 0), 488 lease->lease_addr.plen, lease->iaidaddr->client6_info.iaidinfo.iaid); 489 free(lease); 490 return 0; 491} 492