From: florian Date: Wed, 5 Jun 2024 16:15:47 +0000 (+0000) Subject: Implement lease files. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=763cddbde0e1b7af7c735976159183bf19089258;p=openbsd Implement lease files. --- diff --git a/sbin/dhcp6leased/Makefile b/sbin/dhcp6leased/Makefile index 4574a9a6182..73effc96b8a 100644 --- a/sbin/dhcp6leased/Makefile +++ b/sbin/dhcp6leased/Makefile @@ -1,8 +1,8 @@ -# $OpenBSD: Makefile,v 1.1 2024/06/02 12:28:05 florian Exp $ +# $OpenBSD: Makefile,v 1.2 2024/06/05 16:15:47 florian Exp $ PROG= dhcp6leased SRCS= control.c dhcp6leased.c engine.c frontend.c log.c -SRCS+= parse.y printconf.c +SRCS+= parse.y printconf.c parse_lease.y MAN= dhcp6leased.8 dhcp6leased.conf.5 @@ -17,6 +17,9 @@ YFLAGS= LDADD+= -levent -lutil DPADD+= ${LIBEVENT} ${LIBUTIL} +parse_lease.c: parse_lease.y + ${YACC.y} -ppl -o ${.TARGET} ${.IMPSRC} + .include # Don't compile dhcp6leased as static binary by default diff --git a/sbin/dhcp6leased/control.c b/sbin/dhcp6leased/control.c index 5bc63c11af5..364b9ada478 100644 --- a/sbin/dhcp6leased/control.c +++ b/sbin/dhcp6leased/control.c @@ -1,4 +1,4 @@ -/* $OpenBSD: control.c,v 1.2 2024/06/02 13:35:52 florian Exp $ */ +/* $OpenBSD: control.c,v 1.3 2024/06/05 16:15:47 florian Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include diff --git a/sbin/dhcp6leased/dhcp6leased.c b/sbin/dhcp6leased/dhcp6leased.c index 160ceb410c9..61fbd182a59 100644 --- a/sbin/dhcp6leased/dhcp6leased.c +++ b/sbin/dhcp6leased/dhcp6leased.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dhcp6leased.c,v 1.10 2024/06/05 16:11:26 florian Exp $ */ +/* $OpenBSD: dhcp6leased.c,v 1.11 2024/06/05 16:15:47 florian Exp $ */ /* * Copyright (c) 2017, 2021, 2024 Florian Obser @@ -78,6 +78,7 @@ void configure_address(struct imsg_configure_address *); void deconfigure_address(struct imsg_configure_address *); void read_lease_file(struct imsg_ifinfo *); uint8_t *get_uuid(void); +void write_lease_file(struct imsg_lease_info *); int main_imsg_send_ipc_sockets(struct imsgbuf *, struct imsgbuf *); int main_imsg_compose_frontend(int, int, void *, uint16_t); @@ -309,7 +310,8 @@ main(int argc, char *argv[]) if (unveil(NULL, NULL) == -1) fatal("unveil"); - if (pledge("stdio inet rpath wpath sendfd wroute", NULL) == -1) + if (pledge("stdio inet rpath wpath cpath fattr sendfd wroute", NULL) + == -1) fatal("pledge"); main_imsg_compose_frontend(IMSG_ROUTESOCK, frontend_routesock, NULL, 0); @@ -543,6 +545,17 @@ main_dispatch_engine(int fd, short event, void *bula) deconfigure_address(&imsg_configure_address); break; } + case IMSG_WRITE_LEASE: { + struct imsg_lease_info imsg_lease_info; + if (IMSG_DATA_SIZE(imsg) != + sizeof(imsg_lease_info)) + fatalx("%s: IMSG_WRITE_LEASE wrong length: %lu", + __func__, IMSG_DATA_SIZE(imsg)); + memcpy(&imsg_lease_info, imsg.data, + sizeof(imsg_lease_info)); + write_lease_file(&imsg_lease_info); + break; + } default: log_debug("%s: error handling imsg %d", __func__, imsg.hdr.type); @@ -858,17 +871,99 @@ open_udpsock(uint32_t if_index) freeifaddrs(ifap); } +void +write_lease_file(struct imsg_lease_info *imsg_lease_info) +{ + struct iface_conf *iface_conf; + uint32_t i; + int len, fd, rem; + char if_name[IF_NAMESIZE]; + char lease_buf[LEASE_SIZE]; + char lease_file_buf[sizeof(_PATH_LEASE) + + IF_NAMESIZE]; + char tmpl[] = _PATH_LEASE"XXXXXXXXXX"; + char ntopbuf[INET6_ADDRSTRLEN]; + char *p; + + if (no_lease_files) + return; + + if (if_indextoname(imsg_lease_info->if_index, if_name) == NULL) { + log_warnx("%s: cannot find interface %d", __func__, + imsg_lease_info->if_index); + return; + } + + if ((iface_conf = find_iface_conf(&main_conf->iface_list, if_name)) + == NULL) { + log_debug("%s: no interface configuration for %s", __func__, + if_name); + return; + } + + len = snprintf(lease_file_buf, sizeof(lease_file_buf), "%s%s", + _PATH_LEASE, if_name); + if (len == -1 || (size_t) len >= sizeof(lease_file_buf)) { + log_warnx("%s: failed to encode lease path for %s", __func__, + if_name); + return; + } + + p = lease_buf; + rem = sizeof(lease_buf); + + for (i = 0; i < iface_conf->ia_count; i++) { + len = snprintf(p, rem, "%s%d %s %d\n", LEASE_IA_PD_PREFIX, + i, inet_ntop(AF_INET6, &imsg_lease_info->pds[i].prefix, + ntopbuf, INET6_ADDRSTRLEN), + imsg_lease_info->pds[i].prefix_len); + if (len == -1 || len >= rem) { + log_warnx("%s: failed to encode lease for %s", __func__, + if_name); + return; + } + p += len; + rem -= len; + } + + len = sizeof(lease_buf) - rem; + + if ((fd = mkstemp(tmpl)) == -1) { + log_warn("%s: mkstemp", __func__); + return; + } + + if (write(fd, lease_buf, len) < len) + goto err; + + if (fchmod(fd, 0644) == -1) + goto err; + + if (close(fd) == -1) + goto err; + fd = -1; + + if (rename(tmpl, lease_file_buf) == -1) + goto err; + return; + err: + log_warn("%s", __func__); + if (fd != -1) + close(fd); + unlink(tmpl); +} + void read_lease_file(struct imsg_ifinfo *imsg_ifinfo) { - int len, fd; + int len; char if_name[IF_NAMESIZE]; char lease_file_buf[sizeof(_PATH_LEASE) + IF_NAMESIZE]; if (no_lease_files) return; - memset(imsg_ifinfo->lease, 0, sizeof(imsg_ifinfo->lease)); + memset(imsg_ifinfo->pds, 0, sizeof(imsg_ifinfo->pds)); if (if_indextoname(imsg_ifinfo->if_index, if_name) == NULL) { log_warnx("%s: cannot find interface %d", __func__, @@ -883,13 +978,22 @@ read_lease_file(struct imsg_ifinfo *imsg_ifinfo) if_name); return; } + parse_lease(lease_file_buf, imsg_ifinfo); - if ((fd = open(lease_file_buf, O_RDONLY)) == -1) - return; + if (log_getverbose() > 1) { + int i; + char ntopbuf[INET6_ADDRSTRLEN]; + + for (i = 0; i < MAX_IA; i++) { + if (imsg_ifinfo->pds[i].prefix_len == 0) + continue; - /* no need for error handling, we'll just do a DHCP discover */ - read(fd, imsg_ifinfo->lease, sizeof(imsg_ifinfo->lease) - 1); - close(fd); + log_debug("%s: %s: %d %s/%d", __func__, if_name, i, + inet_ntop(AF_INET6, &imsg_ifinfo->pds[i].prefix, + ntopbuf, INET6_ADDRSTRLEN), + imsg_ifinfo->pds[i].prefix_len); + } + } } void diff --git a/sbin/dhcp6leased/dhcp6leased.h b/sbin/dhcp6leased/dhcp6leased.h index 35f29cc2d8a..040cf8cbb6b 100644 --- a/sbin/dhcp6leased/dhcp6leased.h +++ b/sbin/dhcp6leased/dhcp6leased.h @@ -1,4 +1,4 @@ -/* $OpenBSD: dhcp6leased.h,v 1.6 2024/06/05 16:14:12 florian Exp $ */ +/* $OpenBSD: dhcp6leased.h,v 1.7 2024/06/05 16:15:47 florian Exp $ */ /* * Copyright (c) 2017, 2021 Florian Obser @@ -37,13 +37,8 @@ #define XID_SIZE 3 #define SERVERID_SIZE 130 /* 2 octet type, max 128 octets data */ #define MAX_IA 32 -#define LEASE_VERSION "version: 2" -#define LEASE_IP_PREFIX "ip: " -#define LEASE_NEXTSERVER_PREFIX "next-server: " -#define LEASE_BOOTFILE_PREFIX "filename: " -#define LEASE_HOSTNAME_PREFIX "host-name: " -#define LEASE_DOMAIN_PREFIX "domain-name: " #define LEASE_SIZE 4096 +#define LEASE_IA_PD_PREFIX "ia_pd " /* MAXDNAME from arpa/namesr.h */ #define DHCP6LEASED_MAX_DNSSL 1025 #define MAX_RDNS_COUNT 8 /* max nameserver in a RTM_PROPOSAL */ @@ -177,6 +172,7 @@ enum imsg_type { IMSG_CONFIGURE_ADDRESS, IMSG_DECONFIGURE_ADDRESS, IMSG_REQUEST_REBOOT, + IMSG_WRITE_LEASE, }; struct ctl_engine_info { @@ -217,12 +213,19 @@ struct dhcp6leased_conf { int rapid_commit; }; +struct prefix { + struct in6_addr prefix; + int prefix_len; + uint32_t vltime; + uint32_t pltime; +}; + struct imsg_ifinfo { uint32_t if_index; int rdomain; int running; int link_state; - char lease[LEASE_SIZE]; + struct prefix pds[MAX_IA]; }; struct imsg_dhcp { @@ -231,13 +234,6 @@ struct imsg_dhcp { uint8_t packet[1500]; }; -struct prefix { - struct in6_addr prefix; - int prefix_len; - uint32_t vltime; - uint32_t pltime; -}; - struct imsg_req_dhcp { uint32_t if_index; int elapsed_time; @@ -247,6 +243,11 @@ struct imsg_req_dhcp { struct prefix pds[MAX_IA]; }; +struct imsg_lease_info { + uint32_t if_index; + struct prefix pds[MAX_IA]; +}; + /* dhcp6leased.c */ void imsg_event_add(struct imsgev *); int imsg_compose_event(struct imsgev *, uint16_t, uint32_t, @@ -268,6 +269,25 @@ int *changed_ifaces(struct dhcp6leased_conf *, struct void print_config(struct dhcp6leased_conf *, int); /* parse.y */ -struct dhcp6leased_conf *parse_config(const char *); -int cmdline_symset(char *); +struct file { + TAILQ_ENTRY(file) entry; + FILE *stream; + char *name; + size_t ungetpos; + size_t ungetsize; + u_char *ungetbuf; + int eof_reached; + int lineno; + int errors; +}; +struct dhcp6leased_conf *parse_config(const char *); +struct file *pushfile(const char *, int); +int popfile(void); +int kw_cmp(const void *, const void *); +int lgetc(int); +void lungetc(int); +int findeol(void); + +/* parse_lease.y */ +void parse_lease(const char*, struct imsg_ifinfo *); diff --git a/sbin/dhcp6leased/engine.c b/sbin/dhcp6leased/engine.c index 1e0bb1f2127..6f9ccf16108 100644 --- a/sbin/dhcp6leased/engine.c +++ b/sbin/dhcp6leased/engine.c @@ -1,4 +1,4 @@ -/* $OpenBSD: engine.c,v 1.11 2024/06/05 16:12:09 florian Exp $ */ +/* $OpenBSD: engine.c,v 1.12 2024/06/05 16:15:47 florian Exp $ */ /* * Copyright (c) 2017, 2021, 2024 Florian Obser @@ -136,7 +136,7 @@ void configure_interfaces(struct dhcp6leased_iface *); void deconfigure_interfaces(struct dhcp6leased_iface *); void send_reconfigure_interface(struct iface_pd_conf *, struct prefix *, enum reconfigure_action); -void parse_lease(struct dhcp6leased_iface *, +void parse_lease_xxx(struct dhcp6leased_iface *, struct imsg_ifinfo *); int engine_imsg_compose_main(int, pid_t, void *, uint16_t); const char *dhcp_message_type2str(uint8_t); @@ -445,8 +445,6 @@ engine_dispatch_main(int fd, short event, void *bula) fatalx("%s: IMSG_UPDATE_IF wrong length: %lu", __func__, IMSG_DATA_SIZE(imsg)); memcpy(&imsg_ifinfo, imsg.data, sizeof(imsg_ifinfo)); - if (imsg_ifinfo.lease[LEASE_SIZE - 1] != '\0') - fatalx("Invalid lease"); engine_update_iface(&imsg_ifinfo); break; case IMSG_RECONF_CONF: @@ -601,7 +599,9 @@ void engine_update_iface(struct imsg_ifinfo *imsg_ifinfo) { struct dhcp6leased_iface *iface; - int need_refresh = 0; + struct iface_conf *iface_conf; + int need_refresh = 0; + char ifnamebuf[IF_NAMESIZE], *if_name; iface = get_dhcp6leased_iface_by_id(imsg_ifinfo->if_index); @@ -637,18 +637,38 @@ engine_update_iface(struct imsg_ifinfo *imsg_ifinfo) if (!need_refresh) return; + if ((if_name = if_indextoname(iface->if_index, ifnamebuf)) == NULL) { + log_debug("%s: unknown interface %d", __func__, + iface->if_index); + return; + } + + if ((iface_conf = find_iface_conf(&engine_conf->iface_list, if_name)) + == NULL) { + log_debug("%s: no interface configuration for %d", __func__, + iface->if_index); + return; + } + if (iface->running && LINK_STATE_IS_UP(iface->link_state)) { -#if 0 -XXXX - if (iface->requested_ip.s_addr == INADDR_ANY) - parse_lease(iface, imsg_ifinfo); + uint32_t i; + int got_lease; - if (iface->requested_ip.s_addr == INADDR_ANY) - state_transition(iface, IF_INIT); - else + if (iface->pds[0].prefix_len == 0) + memcpy(iface->pds, imsg_ifinfo->pds, + sizeof(iface->pds)); + + got_lease = 0; + for (i = 0; i < iface_conf->ia_count; i++) { + if (iface->pds[i].prefix_len > 0) { + got_lease = 1; + break; + } + } + if (got_lease) state_transition(iface, IF_REBOOTING); -#endif - state_transition(iface, IF_INIT); + else + state_transition(iface, IF_INIT); } else state_transition(iface, IF_DOWN); } @@ -884,6 +904,7 @@ parse_dhcp(struct dhcp6leased_iface *iface, struct imsg_dhcp *dhcp) case IF_REQUESTING: case IF_RENEWING: case IF_REBINDING: + case IF_REBOOTING: break; case IF_INIT: if (rapid_commit && engine_conf->rapid_commit) @@ -1232,8 +1253,6 @@ request_dhcp_request(struct dhcp6leased_iface *iface) fatalx("invalid state IF_BOUND in %s", __func__); break; case IF_REBOOTING: - fatalx("XXX state IF_REBOOTING in %s not IMPL", __func__); - break; case IF_REQUESTING: case IF_RENEWING: case IF_REBINDING: @@ -1251,6 +1270,7 @@ request_dhcp_request(struct dhcp6leased_iface *iface) engine_imsg_compose_frontend(IMSG_SEND_RENEW, 0, &imsg, sizeof(imsg)); break; + case IF_REBOOTING: case IF_REBINDING: engine_imsg_compose_frontend(IMSG_SEND_REBIND, 0, &imsg, sizeof(imsg)); @@ -1267,6 +1287,7 @@ configure_interfaces(struct dhcp6leased_iface *iface) struct iface_conf *iface_conf; struct iface_ia_conf *ia_conf; struct iface_pd_conf *pd_conf; + struct imsg_lease_info imsg_lease_info; char ifnamebuf[IF_NAMESIZE], *if_name; @@ -1282,6 +1303,12 @@ configure_interfaces(struct dhcp6leased_iface *iface) return; } + memset(&imsg_lease_info, 0, sizeof(imsg_lease_info)); + imsg_lease_info.if_index = iface->if_index; + memcpy(imsg_lease_info.pds, iface->pds, sizeof(iface->pds)); + engine_imsg_compose_main(IMSG_WRITE_LEASE, 0, &imsg_lease_info, + sizeof(imsg_lease_info)); + SIMPLEQ_FOREACH(ia_conf, &iface_conf->iface_ia_list, entry) { struct prefix *pd = &iface->pds[ia_conf->id]; @@ -1371,12 +1398,6 @@ send_reconfigure_interface(struct iface_pd_conf *pd_conf, struct prefix *pd, sizeof(address)); } -void -parse_lease(struct dhcp6leased_iface *iface, struct imsg_ifinfo *imsg_ifinfo) -{ - fatalx("%s: not implemented", __func__); /* XXX */ -} - const char * dhcp_message_type2str(uint8_t type) { diff --git a/sbin/dhcp6leased/parse.y b/sbin/dhcp6leased/parse.y index 940ec15d1f8..3b60e7726a6 100644 --- a/sbin/dhcp6leased/parse.y +++ b/sbin/dhcp6leased/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.7 2024/06/04 15:48:47 florian Exp $ */ +/* $OpenBSD: parse.y,v 1.8 2024/06/05 16:15:47 florian Exp $ */ /* * Copyright (c) 2018, 2024 Florian Obser @@ -52,31 +52,15 @@ #include "frontend.h" TAILQ_HEAD(files, file) files = TAILQ_HEAD_INITIALIZER(files); -static struct file { - TAILQ_ENTRY(file) entry; - FILE *stream; - char *name; - size_t ungetpos; - size_t ungetsize; - u_char *ungetbuf; - int eof_reached; - int lineno; - int errors; -} *file, *topfile; -struct file *pushfile(const char *, int); -int popfile(void); +struct file *file, *topfile; int check_file_secrecy(int, const char *); int yyparse(void); int yylex(void); int yyerror(const char *, ...) __attribute__((__format__ (printf, 1, 2))) __attribute__((__nonnull__ (1))); -int kw_cmp(const void *, const void *); int lookup(char *); int igetc(void); -int lgetc(int); -void lungetc(int); -int findeol(void); TAILQ_HEAD(symhead, sym) symhead = TAILQ_HEAD_INITIALIZER(symhead); struct sym { @@ -699,23 +683,6 @@ symset(const char *nam, const char *val, int persist) return (0); } -int -cmdline_symset(char *s) -{ - char *sym, *val; - int ret; - - if ((val = strrchr(s, '=')) == NULL) - return (-1); - sym = strndup(s, val - s); - if (sym == NULL) - errx(1, "%s: strndup", __func__); - ret = symset(sym, val + 1, 1); - free(sym); - - return (ret); -} - char * symget(const char *nam) { diff --git a/sbin/dhcp6leased/parse_lease.y b/sbin/dhcp6leased/parse_lease.y new file mode 100644 index 00000000000..767e0de8ff2 --- /dev/null +++ b/sbin/dhcp6leased/parse_lease.y @@ -0,0 +1,289 @@ +/* $OpenBSD: parse_lease.y,v 1.1 2024/06/05 16:15:47 florian Exp $ */ + +/* + * Copyright (c) 2018, 2024 Florian Obser + * Copyright (c) 2004, 2005 Esben Norby + * Copyright (c) 2004 Ryan McBride + * Copyright (c) 2002, 2003, 2004 Henning Brauer + * Copyright (c) 2001 Markus Friedl. All rights reserved. + * Copyright (c) 2001 Daniel Hartmeier. All rights reserved. + * Copyright (c) 2001 Theo de Raadt. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +%{ +#include +#include +#include +#include + +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "log.h" +#include "dhcp6leased.h" +#include "frontend.h" + +extern TAILQ_HEAD(files, file) files; +extern struct file *file, *topfile; +int yyparse(void); +int yylex(void); +int yyerror(const char *, ...) + __attribute__((__format__ (printf, 1, 2))) + __attribute__((__nonnull__ (1))); +int pllookup(char *); + +struct imsg_ifinfo *ifinfo; +static int errors; + +typedef struct { + union { + int64_t number; + char *string; + } v; + int lineno; +} YYSTYPE; + +%} + +%token ERROR IAPD + +%token STRING +%token NUMBER + +%% + +grammar : /* empty */ + | grammar '\n' + | grammar ia_pd '\n' + | grammar error '\n' { file->errors++; } + ; + +ia_pd : IAPD NUMBER STRING NUMBER { + if ($2 < 0 || $2 > MAX_IA) { + yyerror("invalid IA_ID %lld", $2); + free($3); + YYERROR; + } + if ($4 < 1 || $4 > 128) { + yyerror("invalid prefix length %lld", $4); + free($3); + ifinfo->pds[$2].prefix_len = 0; + YYERROR; + } else + ifinfo->pds[$2].prefix_len = $4; + + if (inet_pton(AF_INET6, $3, &ifinfo->pds[$2].prefix) + != 1) { + yyerror("invalid prefix %s", $3); + free($3); + ifinfo->pds[$2].prefix_len = 0; + YYERROR; + } + free($3); + } + ; +%% + +struct keywords { + const char *k_name; + int k_val; +}; + +int +yyerror(const char *fmt, ...) +{ + va_list ap; + char *msg; + + file->errors++; + va_start(ap, fmt); + if (vasprintf(&msg, fmt, ap) == -1) + fatalx("yyerror vasprintf"); + va_end(ap); + logit(LOG_CRIT, "%s:%d: %s", file->name, yylval.lineno, msg); + free(msg); + return (0); +} + +int +pllookup(char *s) +{ + /* This has to be sorted always. */ + static const struct keywords keywords[] = { + {"ia_pd", IAPD}, + }; + const struct keywords *p; + + p = bsearch(s, keywords, sizeof(keywords)/sizeof(keywords[0]), + sizeof(keywords[0]), kw_cmp); + + if (p) + return (p->k_val); + else + return (STRING); +} + +int +yylex(void) +{ + char buf[8096]; + char *p; + int quotec, next, c; + int token; + + p = buf; + while ((c = lgetc(0)) == ' ' || c == '\t') + ; /* nothing */ + + yylval.lineno = file->lineno; + if (c == '#') + while ((c = lgetc(0)) != '\n' && c != EOF) + ; /* nothing */ + switch (c) { + case '\'': + case '"': + quotec = c; + while (1) { + if ((c = lgetc(quotec)) == EOF) + return (0); + if (c == '\n') { + file->lineno++; + continue; + } else if (c == '\\') { + if ((next = lgetc(quotec)) == EOF) + return (0); + if (next == quotec || next == ' ' || + next == '\t') + c = next; + else if (next == '\n') { + file->lineno++; + continue; + } else + lungetc(next); + } else if (c == quotec) { + *p = '\0'; + break; + } else if (c == '\0') { + yyerror("syntax error"); + return (findeol()); + } + if (p + 1 >= buf + sizeof(buf) - 1) { + yyerror("string too long"); + return (findeol()); + } + *p++ = c; + } + yylval.v.string = strdup(buf); + if (yylval.v.string == NULL) + err(1, "yylex: strdup"); + return (STRING); + } + +#define allowed_to_end_number(x) \ + (isspace(x) || x == ')' || x ==',' || x == '/' || x == '}' || x == '=') + + if (c == '-' || isdigit(c)) { + do { + *p++ = c; + if ((size_t)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && isdigit(c)); + lungetc(c); + if (p == buf + 1 && buf[0] == '-') + goto nodigits; + if (c == EOF || allowed_to_end_number(c)) { + const char *errstr = NULL; + + *p = '\0'; + yylval.v.number = strtonum(buf, LLONG_MIN, + LLONG_MAX, &errstr); + if (errstr) { + yyerror("\"%s\" invalid number: %s", + buf, errstr); + return (findeol()); + } + return (NUMBER); + } else { +nodigits: + while (p > buf + 1) + lungetc((unsigned char)*--p); + c = (unsigned char)*--p; + if (c == '-') + return (c); + } + } + +#define allowed_in_string(x) \ + (isalnum(x) || (ispunct(x) && x != '(' && x != ')' && \ + x != '{' && x != '}' && \ + x != '!' && x != '=' && x != '#' && \ + x != ',')) + + if (isalnum(c) || c == ':' || c == '_') { + do { + *p++ = c; + if ((size_t)(p-buf) >= sizeof(buf)) { + yyerror("string too long"); + return (findeol()); + } + } while ((c = lgetc(0)) != EOF && (allowed_in_string(c))); + lungetc(c); + *p = '\0'; + if ((token = pllookup(buf)) == STRING) + if ((yylval.v.string = strdup(buf)) == NULL) + err(1, "yylex: strdup"); + return (token); + } + if (c == '\n') { + yylval.lineno = file->lineno; + file->lineno++; + } + if (c == EOF) + return (0); + return (c); +} + +void +parse_lease(const char *filename, struct imsg_ifinfo *imsg) +{ + ifinfo = imsg; + file = pushfile(filename, 0); + if (file == NULL) + return; + + topfile = file; + + yyparse(); + errors = file->errors; + popfile(); +}