./etc/examples/acme-client.conf
./etc/examples/bgpd.conf
./etc/examples/chio.conf
-./etc/examples/dhclient.conf
./etc/examples/dhcpd.conf
./etc/examples/doas.conf
./etc/examples/dvmrpd.conf
./sbin/bioctl
./sbin/chown
./sbin/clri
-./sbin/dhclient
./sbin/dhcp6leased
./sbin/dhcpleased
./sbin/disklabel
./usr/share/man/man5/crontab.5
./usr/share/man/man5/cvs.5
./usr/share/man/man5/defaultdomain.5
-./usr/share/man/man5/dhclient.conf.5
-./usr/share/man/man5/dhclient.leases.5
./usr/share/man/man5/dhcp-options.5
./usr/share/man/man5/dhcp6leased.conf.5
./usr/share/man/man5/dhcpd.conf.5
./usr/share/man/man8/cvsbug.8
./usr/share/man/man8/daily.8
./usr/share/man/man8/dev_mkdb.8
-./usr/share/man/man8/dhclient.8
./usr/share/man/man8/dhcp6leasectl.8
./usr/share/man/man8/dhcp6leased.8
./usr/share/man/man8/dhcpd.8
-# $OpenBSD: Makefile,v 1.489 2024/06/03 10:06:35 florian Exp $
+# $OpenBSD: Makefile,v 1.490 2024/06/30 17:30:54 deraadt Exp $
.include <bsd.own.mk>
pf.os protocols rc rc.conf rpc services shells syslog.conf weekly
# -rw-r--r--
-EXAMPLES=acme-client.conf chio.conf dhclient.conf dhcpd.conf exports \
+EXAMPLES=acme-client.conf chio.conf dhcpd.conf exports \
httpd.conf ifstated.conf inetd.conf man.conf mixerctl.conf \
mrouted.conf ntpd.conf printcap rad.conf rbootd.conf \
remote sensorsd.conf wsconsctl.conf
+++ /dev/null
-# $OpenBSD: dhclient.conf,v 1.2 2017/10/16 23:43:41 krw Exp $
-#
-# DHCP Client Configuration
-#
-# See dhclient.conf(5) for possible contents of this file.
-#
-# Example:
-#
-# send dhcp-lease-time 3600;
-# send host-name "myhost";
-# supersede host-name "myhost";
-# supersede domain-name "my.domain";
-# request subnet-mask, broadcast-address, time-offset, routers,
-# domain-name, domain-name-servers, host-name, lpr-servers, ntp-servers;
-# require subnet-mask, domain-name-servers, routers;
-# $OpenBSD: Makefile,v 1.111 2024/06/03 10:05:18 florian Exp $
+# $OpenBSD: Makefile,v 1.112 2024/06/30 17:30:54 deraadt Exp $
-SUBDIR= atactl badsect bioctl clri dhclient dhcp6leased dhcpleased \
+SUBDIR= atactl badsect bioctl clri dhcp6leased dhcpleased \
disklabel dmesg dump dumpfs fdisk fsck fsck_ext2fs fsck_ffs \
fsck_msdos fsdb fsirand growfs ifconfig iked init ipsecctl \
isakmpd kbd ldattach mknod mount \
+++ /dev/null
-# $OpenBSD: Makefile,v 1.20 2017/07/08 20:38:31 krw Exp $
-#
-# Copyright (c) 1996, 1997 The Internet Software Consortium.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# 1. Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-# 2. Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-# 3. Neither the name of The Internet Software Consortium nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
-# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
-# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
-# THE INTERNET SOFTWARE CONSORTIUM OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
-# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
-# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
-# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
-# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
-# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
-# OF THE POSSIBILITY OF SUCH DAMAGE.
-#
-
-.include <bsd.own.mk>
-
-SRCS= dhclient.c clparse.c dispatch.c bpf.c options.c \
- conflex.c log.c packet.c \
- parse.c privsep.c kroute.c
-
-PROG= dhclient
-LDADD+= -lutil
-DPADD+= ${LIBUTIL}
-MAN= dhclient.8 dhclient.conf.5 dhclient.leases.5
-
-CFLAGS+=-Wall
-CFLAGS+=-Wstrict-prototypes -Wmissing-prototypes
-CFLAGS+=-Wmissing-declarations
-CFLAGS+=-Wshadow -Wpointer-arith -Wcast-qual
-CFLAGS+=-Wsign-compare
-
-.include <bsd.prog.mk>
+++ /dev/null
-/* $OpenBSD: bpf.c,v 1.75 2019/03/18 00:00:59 dlg Exp $ */
-
-/* BPF socket interface code, originally contributed by Archie Cobbs. */
-
-/*
- * Copyright (c) 1995, 1996, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/ioctl.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <net/bpf.h>
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/if_ether.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-
-int
-get_bpf_sock(char *name)
-{
- struct ifreq ifr;
- int sock;
-
- if ((sock = open("/dev/bpf", O_RDWR | O_CLOEXEC)) == -1)
- fatal("open(/dev/bpf)");
-
- /* Set the BPF device to point at this interface. */
- strlcpy(ifr.ifr_name, name, IFNAMSIZ);
- if (ioctl(sock, BIOCSETIF, &ifr) == -1)
- fatal("BIOCSETIF");
-
- return sock;
-}
-
-int
-get_udp_sock(int rdomain)
-{
- int sock, on = 1;
-
- /*
- * Use raw socket for unicast send.
- */
- if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1)
- fatal("socket(AF_INET, SOCK_RAW)");
- if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on,
- sizeof(on)) == -1)
- fatal("setsockopt(IP_HDRINCL)");
- if (setsockopt(sock, IPPROTO_IP, SO_RTABLE, &rdomain,
- sizeof(rdomain)) == -1)
- fatal("setsockopt(SO_RTABLE)");
-
- return sock;
-}
-
-/*
- * Packet filter program.
- *
- * N.B.: Changes to the filter program may require changes to the
- * constant offsets used in if_register_receive to patch the BPF program!
- */
-struct bpf_insn dhcp_bpf_filter[] = {
- /* Make sure this is an IP packet. */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 8),
-
- /* Make sure it's a UDP packet. */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 6),
-
- /* Make sure this isn't a fragment. */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 4, 0),
-
- /* Get the IP header length. */
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
-
- /* Make sure it's to the right port. */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1), /* patch */
-
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (unsigned int)-1),
-
- /* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
-};
-
-int dhcp_bpf_filter_len = sizeof(dhcp_bpf_filter) / sizeof(struct bpf_insn);
-
-/*
- * Packet write filter program:
- * 'ip and udp and src port bootps and dst port (bootps or bootpc)'
- */
-struct bpf_insn dhcp_bpf_wfilter[] = {
- BPF_STMT(BPF_LD + BPF_B + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, (IPVERSION << 4) + 5, 0, 12),
-
- /* Make sure this is an IP packet. */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, ETHERTYPE_IP, 0, 10),
-
- /* Make sure it's a UDP packet. */
- BPF_STMT(BPF_LD + BPF_B + BPF_ABS, 23),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, IPPROTO_UDP, 0, 8),
-
- /* Make sure this isn't a fragment. */
- BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 20),
- BPF_JUMP(BPF_JMP + BPF_JSET + BPF_K, 0x1fff, 6, 0), /* patched */
-
- /* Get the IP header length. */
- BPF_STMT(BPF_LDX + BPF_B + BPF_MSH, 14),
-
- /* Make sure it's from the right port. */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 14),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 68, 0, 3),
-
- /* Make sure it is to the right ports. */
- BPF_STMT(BPF_LD + BPF_H + BPF_IND, 16),
- BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, 67, 0, 1),
-
- /* If we passed all the tests, ask for the whole packet. */
- BPF_STMT(BPF_RET+BPF_K, (unsigned int)-1),
-
- /* Otherwise, drop it. */
- BPF_STMT(BPF_RET+BPF_K, 0),
-};
-
-int dhcp_bpf_wfilter_len = sizeof(dhcp_bpf_wfilter) / sizeof(struct bpf_insn);
-
-int
-configure_bpf_sock(int bpffd)
-{
- struct bpf_version v;
- struct bpf_program p;
- int flag = 1, sz;
- int fildrop = BPF_FILDROP_CAPTURE;
-
- /* Make sure the BPF version is in range. */
- if (ioctl(bpffd, BIOCVERSION, &v) == -1)
- fatal("BIOCVERSION");
-
- if (v.bv_major != BPF_MAJOR_VERSION ||
- v.bv_minor < BPF_MINOR_VERSION)
- fatalx("kernel BPF version out of range - recompile "
- "dhclient");
-
- /*
- * Set immediate mode so that reads return as soon as a packet
- * comes in, rather than waiting for the input buffer to fill
- * with packets.
- */
- if (ioctl(bpffd, BIOCIMMEDIATE, &flag) == -1)
- fatal("BIOCIMMEDIATE");
-
- if (ioctl(bpffd, BIOCSFILDROP, &fildrop) == -1)
- fatal("BIOCSFILDROP");
-
- /* Get the required BPF buffer length from the kernel. */
- if (ioctl(bpffd, BIOCGBLEN, &sz) == -1)
- fatal("BIOCGBLEN");
-
- /* Set up the bpf filter program structure. */
- p.bf_len = dhcp_bpf_filter_len;
- p.bf_insns = dhcp_bpf_filter;
-
- /* Patch the server port into the BPF program.
- *
- * N.B.: changes to filter program may require changes to the
- * insn number(s) used below!
- */
- dhcp_bpf_filter[8].k = LOCAL_PORT;
-
- if (ioctl(bpffd, BIOCSETF, &p) == -1)
- fatal("BIOCSETF");
-
- /* Set up the bpf write filter program structure. */
- p.bf_len = dhcp_bpf_wfilter_len;
- p.bf_insns = dhcp_bpf_wfilter;
-
- if (dhcp_bpf_wfilter[7].k == 0x1fff)
- dhcp_bpf_wfilter[7].k = htons(IP_MF|IP_OFFMASK);
-
- if (ioctl(bpffd, BIOCSETWF, &p) == -1)
- fatal("BIOCSETWF");
-
- if (ioctl(bpffd, BIOCLOCK, NULL) == -1)
- fatal("BIOCLOCK");
-
- return sz;
-}
-
-ssize_t
-send_packet(struct interface_info *ifi, struct in_addr from, struct in_addr to,
- const char *desc)
-{
- struct iovec iov[4];
- struct sockaddr_in dest;
- struct ether_header eh;
- struct ip ip;
- struct udphdr udp;
- struct msghdr msg;
- struct dhcp_packet *packet = &ifi->sent_packet;
- ssize_t result, total;
- unsigned int iovcnt = 0, i;
- int len = ifi->sent_packet_length;
-
- memset(&dest, 0, sizeof(dest));
- dest.sin_family = AF_INET;
- dest.sin_port = htons(REMOTE_PORT);
- dest.sin_addr.s_addr = to.s_addr;
-
- if (to.s_addr == INADDR_BROADCAST) {
- assemble_eh_header(ifi->hw_address, &eh);
- iov[0].iov_base = &eh;
- iov[0].iov_len = sizeof(eh);
- iovcnt++;
- }
-
- ip.ip_v = 4;
- ip.ip_hl = 5;
- ip.ip_tos = IPTOS_LOWDELAY;
- ip.ip_len = htons(sizeof(ip) + sizeof(udp) + len);
- ip.ip_id = 0;
- ip.ip_off = 0;
- ip.ip_ttl = 128;
- ip.ip_p = IPPROTO_UDP;
- ip.ip_sum = 0;
- ip.ip_src.s_addr = from.s_addr;
- ip.ip_dst.s_addr = to.s_addr;
- ip.ip_sum = wrapsum(checksum((unsigned char *)&ip, sizeof(ip), 0));
- iov[iovcnt].iov_base = &ip;
- iov[iovcnt].iov_len = sizeof(ip);
- iovcnt++;
-
- udp.uh_sport = htons(LOCAL_PORT);
- udp.uh_dport = htons(REMOTE_PORT);
- udp.uh_ulen = htons(sizeof(udp) + len);
- udp.uh_sum = 0;
- udp.uh_sum = wrapsum(checksum((unsigned char *)&udp, sizeof(udp),
- checksum((unsigned char *)packet, len,
- checksum((unsigned char *)&ip.ip_src,
- 2 * sizeof(ip.ip_src),
- IPPROTO_UDP + (uint32_t)ntohs(udp.uh_ulen)))));
- iov[iovcnt].iov_base = &udp;
- iov[iovcnt].iov_len = sizeof(udp);
- iovcnt++;
-
- iov[iovcnt].iov_base = packet;
- iov[iovcnt].iov_len = len;
- iovcnt++;
-
- total = 0;
- for (i = 0; i < iovcnt; i++)
- total += iov[i].iov_len;
-
- if (to.s_addr == INADDR_BROADCAST) {
- result = writev(ifi->bpffd, iov, iovcnt);
- if (result == -1)
- log_warn("%s: writev(%s)", log_procname, desc);
- else if (result < total) {
- log_warnx("%s, writev(%s): %zd of %zd bytes",
- log_procname, desc, result, total);
- result = -1;
- }
- } else {
- memset(&msg, 0, sizeof(msg));
- msg.msg_name = (struct sockaddr *)&dest;
- msg.msg_namelen = sizeof(dest);
- msg.msg_iov = iov;
- msg.msg_iovlen = iovcnt;
- result = sendmsg(ifi->udpfd, &msg, 0);
- if (result == -1)
- log_warn("%s: sendmsg(%s)", log_procname, desc);
- else if (result < total) {
- result = -1;
- log_warnx("%s, sendmsg(%s): %zd of %zd bytes",
- log_procname, desc, result, total);
- }
- }
-
- return result;
-}
-
-/*
- * Extract a DHCP packet from a bpf capture buffer.
- *
- * Each captured packet is
- *
- * <BPF header>
- * <padding to BPF_WORDALIGN>
- * <captured DHCP packet>
- * <padding to BPF_WORDALIGN>
- *
- * Return the number of bytes processed or 0 if there is
- * no valid DHCP packet in the buffer.
- */
-ssize_t
-receive_packet(unsigned char *buf, unsigned char *lim,
- struct sockaddr_in *from, struct ether_addr *hfrom,
- struct dhcp_packet *packet)
-{
- struct bpf_hdr bh;
- struct ether_header eh;
- unsigned char *pktlim, *data, *next;
- size_t datalen;
- int len;
-
- for (next = buf; next < lim; next = pktlim) {
- /* No bpf header means no more packets. */
- if (lim < next + sizeof(bh))
- return 0;
-
- memcpy(&bh, next, sizeof(bh));
- pktlim = next + BPF_WORDALIGN(bh.bh_hdrlen + bh.bh_caplen);
-
- /* Truncated bpf packet means no more packets. */
- if (lim < next + bh.bh_hdrlen + bh.bh_caplen)
- return 0;
-
- /* Drop incompletely captured DHCP packets. */
- if (bh.bh_caplen != bh.bh_datalen)
- continue;
-
- /*
- * Drop packets with invalid ethernet/ip/udp headers.
- */
- if (pktlim < next + bh.bh_hdrlen + sizeof(eh))
- continue;
- memcpy(&eh, next + bh.bh_hdrlen, sizeof(eh));
- memcpy(hfrom->ether_addr_octet, eh.ether_shost, ETHER_ADDR_LEN);
-
- len = decode_udp_ip_header(next + bh.bh_hdrlen + sizeof(eh),
- bh.bh_caplen - sizeof(eh), from);
- if (len < 0)
- continue;
-
- /* Drop packets larger than sizeof(struct dhcp_packet). */
- datalen = bh.bh_caplen - (sizeof(eh) + len);
- if (datalen > sizeof(*packet))
- continue;
-
- /* Extract the DHCP packet for further processing. */
- data = next + bh.bh_hdrlen + sizeof(eh) + len;
- memset(packet, DHO_END, sizeof(*packet));
- memcpy(packet, data, datalen);
-
- return (pktlim - buf);
- }
-
- return 0;
-}
+++ /dev/null
-/* $OpenBSD: clparse.c,v 1.203 2021/02/27 17:44:58 krw Exp $ */
-
-/* Parser for dhclient config and lease files. */
-
-/*
- * Copyright (c) 1997 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "dhctoken.h"
-#include "log.h"
-
-void parse_conf_decl(FILE *, char *);
-int parse_hex_octets(FILE *, unsigned int *, uint8_t **);
-int parse_domain_list(FILE *, int *, char **);
-int parse_option_list(FILE *, int *, uint8_t *);
-int parse_interface(FILE *, char *);
-int parse_lease(FILE *, struct client_lease **);
-void parse_lease_decl(FILE *, struct client_lease *);
-int parse_option(FILE *, int *, struct option_data *);
-int parse_reject_statement(FILE *);
-
-void apply_actions(uint8_t *);
-void set_default_client_identifier(struct ether_addr *);
-void set_default_hostname(void);
-
-void
-init_config(void)
-{
- struct option_data *option;
- uint32_t expiry;
-
- config = calloc(1, sizeof(*config));
- if (config == NULL)
- fatal("config");
-
- TAILQ_INIT(&config->reject_list);
-
- /* Set some defaults. */
- config->link_interval = 10; /* secs before going daemon w/o lease */
- config->select_interval = 0; /* secs to wait for other OFFERs */
- config->retry_interval = 1; /* secs before asking for OFFER */
-#ifdef SMALL
- config->backoff_cutoff = 2; /* max secs between packet retries */
- config->reboot_interval = 5; /* secs before giving up on reboot */
- config->offer_interval = 10; /* secs to wait for an OFFER */
-#else
- config->backoff_cutoff = 10; /* max secs between packet retries */
- config->reboot_interval = 1; /* secs before giving up on reboot */
- config->offer_interval = 30; /* secs to wait for an OFFER */
-#endif
- config->initial_interval = 1; /* secs before 1st retry */
-
- /* All leases must supply a subnet mask. Classful defaults are dead, Jim. */
- config->required_options[config->required_option_count++] = DHO_SUBNET_MASK;
-
- /*
- * Set default lease length, which will determine default renewal
- * and rebind times.
- *
- * XXX Thus applies to both BOOTP and DHCP leases.
- *
- * DHO_DHCP_LEASE_TIME (12 hours == 43200 seconds),
- */
- option = &config->defaults[DHO_DHCP_LEASE_TIME];
- option->data = malloc(4);
- if (option->data == NULL)
- fatal("default lease length");
-
- config->default_actions[DHO_DHCP_LEASE_TIME] = ACTION_DEFAULT;
- option->len = 4;
- expiry = htonl(43200);
- memcpy(option->data, &expiry, 4);
-
- config->requested_options
- [config->requested_option_count++] = DHO_SUBNET_MASK;
- config->requested_options
- [config->requested_option_count++] = DHO_BROADCAST_ADDRESS;
- config->requested_options
- [config->requested_option_count++] = DHO_TIME_OFFSET;
- /* RFC 3442 says CLASSLESS_STATIC_ROUTES must be before ROUTERS! */
- config->requested_options
- [config->requested_option_count++] = DHO_CLASSLESS_STATIC_ROUTES;
- config->requested_options
- [config->requested_option_count++] = DHO_ROUTERS;
- config->requested_options
- [config->requested_option_count++] = DHO_DOMAIN_NAME;
- config->requested_options
- [config->requested_option_count++] = DHO_DOMAIN_SEARCH;
- config->requested_options
- [config->requested_option_count++] = DHO_DOMAIN_NAME_SERVERS;
- config->requested_options
- [config->requested_option_count++] = DHO_HOST_NAME;
- config->requested_options
- [config->requested_option_count++] = DHO_BOOTFILE_NAME;
- config->requested_options
- [config->requested_option_count++] = DHO_TFTP_SERVER;
-}
-
-/*
- * conf-decls :==
- * <nil>
- * | conf-decl
- * | conf-decls conf-decl
- */
-void
-read_conf(char *name, uint8_t *actions, struct ether_addr *hwaddr)
-{
- FILE *cfile;
- int token;
-
- init_config();
-
- if (path_dhclient_conf != NULL) {
- cfile = fopen(path_dhclient_conf, "r");
- if (cfile == NULL)
- fatal("fopen(%s)", path_dhclient_conf);
- new_parse(path_dhclient_conf);
- for (;;) {
- token = peek_token(NULL, cfile);
- if (token == EOF)
- break;
- parse_conf_decl(cfile, name);
- }
- fclose(cfile);
- }
-
- set_default_client_identifier(hwaddr);
- set_default_hostname();
- apply_actions(actions);
-}
-
-/*
- * leases :==
- * <nil>
- * | lease
- * | leases lease
- */
-void
-read_lease_db(struct client_lease_tq *lease_db)
-{
- struct client_lease *lease, *lp, *nlp;
- FILE *cfile;
- int i;
-
- TAILQ_INIT(lease_db);
-
- if ((cfile = fopen(path_lease_db, "r")) == NULL)
- return;
-
- new_parse(path_lease_db);
-
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- while (feof(cfile) == 0) {
- if (parse_lease(cfile, &lease) == 0)
- continue;
-
- /*
- * The new lease will supersede a lease with the same
- * ssid AND the same Client Identifier AND the same
- * IP address.
- */
- TAILQ_FOREACH_SAFE(lp, lease_db, next, nlp) {
- if (lp->ssid_len != lease->ssid_len)
- continue;
- if (memcmp(lp->ssid, lease->ssid, lp->ssid_len) != 0)
- continue;
- if ((lease->options[i].len != 0) &&
- ((lp->options[i].len != lease->options[i].len) ||
- memcmp(lp->options[i].data, lease->options[i].data,
- lp->options[i].len) != 0))
- continue;
- if (lp->address.s_addr != lease->address.s_addr)
- continue;
-
- TAILQ_REMOVE(lease_db, lp, next);
- free_client_lease(lp);
- }
-
- if (lease->epoch == 0)
- time(&lease->epoch);
- TAILQ_INSERT_TAIL(lease_db, lease, next);
- }
-
- fclose(cfile);
-}
-
-/*
- * conf-decl :==
- * APPEND option SEMI
- * | BACKOFF_CUTOFF number SEMI
- * | DEFAULT option SEMI
- * | FILENAME string SEMI
- * | FIXED_ADDR ip-address SEMI
- * | IGNORE option-name-list SEMI
- * | INITIAL_INTERVAL number SEMI
- * | INTERFACE interface
- * | LINK_TIMEOUT number SEMI
- * | NEXT_SERVER string SEMI
- * | PREPEND option SEMI
- * | REBOOT number SEMI
- * | REJECT ip-address SEMI
- * | REQUEST option-name-list SEMI
- * | REQUIRE option-name-list SEMI
- * | RETRY number SEMI
- * | SELECT_TIMEOUT number SEMI
- * | SEND option SEMI
- * | SERVER_NAME string SEMI
- * | SUPERSEDE option SEMI
- * | TIMEOUT number SEMI
- */
-void
-parse_conf_decl(FILE *cfile, char *name)
-{
- uint8_t list[DHO_COUNT];
- char *val;
- enum actions *p;
- int action, count, i, token;
-
- token = next_token(NULL, cfile);
-
- switch (token) {
- case TOK_APPEND:
- if (parse_option(cfile, &i, config->defaults) == 0)
- return;
- action = code_to_action(i, ACTION_APPEND);
- if (action == ACTION_DEFAULT)
- parse_warn("'append' treated as 'default'");
- config->default_actions[i] = action;
- break;
- case TOK_BACKOFF_CUTOFF:
- if (parse_number(cfile, &config->backoff_cutoff, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_DEFAULT:
- if (parse_option(cfile, &i, config->defaults) == 0)
- return;
- config->default_actions[i] = ACTION_DEFAULT;
- break;
- case TOK_FILENAME:
- if (parse_string(cfile, &val) == 0)
- return;
- free(config->filename);
- config->filename = val;
- break;
- case TOK_FIXED_ADDR:
- if (parse_ip_addr(cfile, &config->address) == 0)
- return;
- break;
- case TOK_IGNORE:
- memset(list, 0, sizeof(list));
- count = 0;
- if (parse_option_list(cfile, &count, list) == 0)
- return;
- p = config->default_actions;
- if (count == 0) {
- for (i = 0; i < DHO_COUNT; i++)
- if (p[i] == ACTION_IGNORE)
- p[i] = ACTION_USELEASE;
- } else {
- for (i = 0; i < count; i++)
- p[list[i]] = ACTION_IGNORE;
- }
- break;
- case TOK_INITIAL_INTERVAL:
- if (parse_number(cfile, &config->initial_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_INTERFACE:
- parse_interface(cfile, name);
- return;
- case TOK_LINK_TIMEOUT:
- if (parse_number(cfile, &config->link_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_NEXT_SERVER:
- if (parse_ip_addr(cfile, &config->next_server) == 0)
- return;
- break;
- case TOK_PREPEND:
- if (parse_option(cfile, &i, config->defaults) == 0)
- return;
- action = code_to_action(i, ACTION_PREPEND);
- if (action == ACTION_SUPERSEDE)
- parse_warn("'prepend' treated as 'supersede'");
- config->default_actions[i] = action;
- break;
- case TOK_REBOOT:
- if (parse_number(cfile, &config->reboot_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_REJECT:
- if (parse_reject_statement(cfile) == 0)
- return;
- break;
- case TOK_REQUEST:
- if (parse_option_list(cfile, &config->requested_option_count,
- config->requested_options) == 0)
- return;
- break;
- case TOK_REQUIRE:
- if (parse_option_list(cfile, &config->required_option_count,
- config->required_options) == 0)
- return;
- break;
- case TOK_RETRY:
- if (parse_number(cfile, &config->retry_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_SELECT_TIMEOUT:
- if (parse_number(cfile, &config->select_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_SEND:
- if (parse_option(cfile, &i, config->send_options) == 0)
- return;
- break;
- case TOK_SERVER_NAME:
- if (parse_string(cfile, &val) == 0)
- return;
- free(config->server_name);
- config->server_name = val;
- break;
- case TOK_SUPERSEDE:
- if (parse_option(cfile, &i, config->defaults) == 0)
- return;
- config->default_actions[i] = ACTION_SUPERSEDE;
- break;
- case TOK_TIMEOUT:
- if (parse_number(cfile, &config->offer_interval, 0, INT32_MAX)
- == 0)
- return;
- break;
- case TOK_USELEASE:
- memset(list, 0, sizeof(list));
- count = 0;
- if (parse_option_list(cfile, &count, list) == 0)
- return;
- p = config->default_actions;
- if (count == 0) {
- for (i = 0; i < DHO_COUNT; i++) {
- free(config->defaults[i].data);
- config->defaults[i].data = NULL;
- config->defaults[i].len = 0;
- p[i] = ACTION_USELEASE;
- }
- } else {
- for (i = 0; i < count; i++) {
- free(config->defaults[list[i]].data);
- config->defaults[list[i]].data = NULL;
- config->defaults[list[i]].len = 0;
- p[list[i]] = ACTION_USELEASE;
- }
- }
- break;
- default:
- parse_warn("expecting statement.");
- skip_to_semi(cfile);
- return;
- }
-
- parse_semi(cfile);
-}
-
-int
-parse_hex_octets(FILE *cfile, unsigned int *len, uint8_t **buf)
-{
- static uint8_t octets[1500];
- char *val, *ep;
- unsigned long ulval;
- unsigned int i;
- int token;
-
- i = 0;
- do {
- token = next_token(&val, cfile);
-
- errno = 0;
- ulval = strtoul(val, &ep, 16);
- if ((val[0] == '\0' || *ep != '\0') ||
- (errno == ERANGE && ulval == ULONG_MAX) ||
- (ulval > UINT8_MAX))
- break;
- octets[i++] = ulval;
-
- if (peek_token(NULL, cfile) == ';') {
- *buf = malloc(i);
- if (*buf == NULL)
- break;
- memcpy(*buf, octets, i);
- *len = i;
- return 1;
- }
- if (i == sizeof(octets))
- break;
- token = next_token(NULL, cfile);
- } while (token == ':');
-
- parse_warn("expecting colon delimited list of hex octets.");
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-int
-parse_domain_list(FILE *cfile, int *len, char **dp)
-{
- uint8_t buf[DHCP_DOMAIN_SEARCH_LEN];
- char *domain;
- int count, token;
-
- memset(buf, 0, sizeof(buf));
- count = 0;
-
- do {
- if (parse_string(cfile, &domain) == 0)
- return 0;
-
- count++;
- if (count > DHCP_DOMAIN_SEARCH_CNT) {
- parse_warn("more than 6 search domains");
- break;
- }
-
- if (count > 1)
- strlcat(buf, " ", sizeof(buf));
- if (strlcat(buf, domain, sizeof(buf)) >= sizeof(buf)) {
- parse_warn("domain list too long");
- break;
- }
-
- token = peek_token(NULL, cfile);
- if (token == ';') {
- *dp = strdup(buf);
- if (*dp == NULL)
- fatal("domain name list");
- *len = strlen(*dp);
- return 1;
- }
- token = next_token(NULL, cfile);
- if (token != ',')
- parse_warn("';' or ',' expected");
- } while (token == ',');
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-/*
- * option-list :==
- * <nil>
- * | option-name
- * | option-list COMMA option-name
- */
-int
-parse_option_list(FILE *cfile, int *count, uint8_t *optlist)
-{
- uint8_t list[DHO_COUNT];
- unsigned int ix, j;
- int i;
- int token;
- char *val;
-
- /* Empty list of option names is allowed, to re-init optlist. */
- if (peek_token(NULL, cfile) == ';') {
- memset(optlist, DHO_PAD, sizeof(list));
- *count = 0;
- return 1;
- }
-
- memset(list, 0, sizeof(list));
- memcpy(list, optlist, *count);
- ix = *count;
- do {
- /* Next token must be an option name. */
- token = next_token(&val, cfile);
- i = name_to_code(val);
- if (i == DHO_END)
- break;
-
- /* Avoid storing duplicate options in the list. */
- for (j = 0; j < ix && list[j] != i; j++)
- ;
- if (j == ix)
- list[ix++] = i;
-
- if (peek_token(NULL, cfile) == ';') {
- memcpy(optlist, list, sizeof(list));
- *count = ix;
- return 1;
- }
- token = next_token(NULL, cfile);
- } while (token == ',');
-
- parse_warn("expecting comma delimited list of option names.");
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-/*
- * interface :==
- * string LBRACE conf-decls RBRACE
- */
-int
-parse_interface(FILE *cfile, char *name)
-{
- char *val;
- int token;
-
- token = next_token(&val, cfile);
- if (token != TOK_STRING) {
- parse_warn("expecting string.");
- if (token != ';')
- skip_to_semi(cfile);
- return 0;
- }
-
- if (strcmp(name, val) != 0) {
- skip_to_semi(cfile);
- return 1;
- }
-
- token = next_token(&val, cfile);
- if (token != '{') {
- parse_warn("expecting '{'.");
- if (token != ';')
- skip_to_semi(cfile);
- return 0;
- }
-
- for (;;) {
- token = peek_token(&val, cfile);
- if (token == EOF) {
- parse_warn("unterminated interface declaration.");
- return 0;
- }
- if (token == '}') {
- token = next_token(NULL, cfile);
- return 1;
- }
- parse_conf_decl(cfile, name);
- }
-
- return 0;
-}
-
-/*
- * lease :== LEASE RBRACE lease-decls LBRACE
- *
- * lease-decls :==
- * <nil>
- * | lease-decl
- * | lease-decls lease-decl
- */
-int
-parse_lease(FILE *cfile, struct client_lease **lp)
-{
- struct client_lease *lease;
- int token;
-
- token = next_token(NULL, cfile);
- if (token == EOF)
- return 0;
- if (token != TOK_LEASE) {
- parse_warn("expecting lease");
- if (token != ';')
- skip_to_semi(cfile);
- return 0;
- }
-
- token = next_token(NULL, cfile);
- if (token != '{') {
- parse_warn("expecting '{'.");
- if (token != ';')
- skip_to_semi(cfile);
- return 0;
- }
-
- lease = calloc(1, sizeof(*lease));
- if (lease == NULL)
- fatal("lease");
-
- for (;;) {
- token = peek_token(NULL, cfile);
- if (token == EOF) {
- parse_warn("unterminated lease.");
- free_client_lease(lease);
- break;
- }
- if (token == '}') {
- token = next_token(NULL, cfile);
- *lp = lease;
- return 1;
- }
- parse_lease_decl(cfile, lease);
- }
-
- return 0;
-}
-
-/*
- * lease-decl :==
- * BOOTP SEMI
- * | EPOCH number SEMI
- * | EXPIRE <skip to semi> SEMI
- * | FILENAME string SEMI
- * | FIXED_ADDR ip_address SEMI
- * | INTERFACE string SEMI
- * | NEXT_SERVER string SEMI
- * | OPTION option SEMI
- * | REBIND <skip to semi> SEMI
- * | RENEW <skip to semi> SEMI
- * | SERVER_NAME string SEMI
- * | SSID string SEMI
- */
-void
-parse_lease_decl(FILE *cfile, struct client_lease *lease)
-{
- char *val;
- unsigned int len;
- int i, token;
-
- token = next_token(&val, cfile);
-
- switch (token) {
- case TOK_BOOTP:
- /* 'bootp' is just a comment. See BOOTP_LEASE(). */
- break;
- case TOK_EPOCH:
- if (parse_number(cfile, &lease->epoch, INT64_MIN, INT64_MAX)
- == 0)
- return;
- break;
- case TOK_EXPIRE:
- /* 'expire' is just a comment. See 'epoch'. */
- skip_to_semi(cfile);
- return;
- case TOK_FILENAME:
- if (parse_string(cfile, &val) == 0)
- return;
- free(lease->filename);
- lease->filename = val;
- break;
- case TOK_FIXED_ADDR:
- if (parse_ip_addr(cfile, &lease->address) == 0)
- return;
- break;
- case TOK_INTERFACE:
- /* 'interface' is just a comment. */
- skip_to_semi(cfile);
- return;
- case TOK_NEXT_SERVER:
- if (parse_ip_addr(cfile, &lease->next_server) == 0)
- return;
- break;
- case TOK_OPTION:
- if (parse_option(cfile, &i, lease->options) == 0)
- return;
- break;
- case TOK_REBIND:
- case TOK_RENEW:
- /* 'rebind' & 'renew' are just comments. See 'epoch'. */
- skip_to_semi(cfile);
- return;
- case TOK_SERVER_NAME:
- if (parse_string(cfile, &val) == 0)
- return;
- free(lease->server_name);
- lease->server_name = val;
- break;
- case TOK_SSID:
- if (parse_string(cfile, &val) == 0)
- return;
- len = strlen(val);
- if (len > sizeof(lease->ssid)) {
- free(val);
- parse_warn("ssid > 32 bytes");
- skip_to_semi(cfile);
- return;
- }
- memset(lease->ssid, 0, sizeof(lease->ssid));
- memcpy(lease->ssid, val, len);
- free(val);
- lease->ssid_len = len;
- break;
- default:
- parse_warn("expecting lease declaration.");
- skip_to_semi(cfile);
- return;
- }
-
- parse_semi(cfile);
-}
-
-/*
- * option :==
- * option-name option-value
- *
- * option-value :==
- * text
- * | hex-octets
- * | signed-32
- * | unsigned-32
- * | unsigned-16
- * | unsigned-8
- * | flag
- * | ip-address
- * | ip-address-array
- * | ip-address-pair-array
- * | uint16-array
- * | cidr-ip-address-array
- */
-int
-parse_option(FILE *cfile, int *code, struct option_data *options)
-{
- uint8_t hunkbuf[1024], cidr[5], buf[4];
- struct in_addr ip_addr;
- uint8_t *dp;
- char *fmt, *val;
- long long number;
- unsigned int hunkix = 0;
- int i, freedp, len, token;
-
- token = next_token(&val, cfile);
- i = name_to_code(val);
- if (i == DHO_END) {
- parse_warn("expecting option name.");
- skip_to_semi(cfile);
- return 0;
- }
-
- /* Parse the option data. */
- do {
- for (fmt = code_to_format(i); *fmt != '\0'; fmt++) {
- if (*fmt == 'A')
- break;
- freedp = 0;
- switch (*fmt) {
- case 'X':
- if (peek_token(NULL, cfile) == TOK_STRING) {
- if (parse_string(cfile, (char **)&dp)
- == 0)
- return 0;
- len = strlen(dp);
- } else if (parse_hex_octets(cfile, &len, &dp)
- == 0)
- return 0;
- freedp = 1;
- break;
- case 't': /* Text string. */
- if (parse_string(cfile, (char **)&dp) == 0)
- return 0;
- len = strlen(dp);
- freedp = 1;
- break;
- case 'I': /* IP address. */
- if (parse_ip_addr(cfile, &ip_addr) == 0)
- return 0;
- len = sizeof(ip_addr);
- dp = (uint8_t *)&ip_addr;
- break;
- case 'l': /* Signed 32-bit integer. */
- if (parse_number(cfile, &number, INT32_MIN,
- INT32_MAX) == 0)
- return 0;
- number = htobe64(number);
- len = sizeof(int32_t);
- memcpy(buf, (char *)&number + (sizeof(number) - len), len);
- dp = buf;
- break;
- case 'L': /* Unsigned 32-bit integer. */
- if (parse_number(cfile, &number, 0, UINT32_MAX) == 0)
- return 0;
- number = htobe64(number);
- len = sizeof(uint32_t);
- memcpy(buf, (char *)&number + (sizeof(number) - len), len);
- dp = buf;
- break;
- case 'S': /* Unsigned 16-bit integer. */
- if (parse_number(cfile, &number, 0, UINT16_MAX) == 0)
- return 0;
- number = htobe64(number);
- len = sizeof(uint16_t);
- memcpy(buf, (char *)&number + (sizeof(number) - len), len);
- dp = buf;
- break;
- case 'B': /* Unsigned 8-bit integer. */
- if (parse_number(cfile, &number, 0, UINT8_MAX) == 0)
- return 0;
- buf[0] = number;
- len = 1;
- dp = buf;
- break;
- case 'f': /* Boolean flag. */
- if (parse_boolean(cfile, buf) == 0)
- return 0;
- len = 1;
- dp = buf;
- break;
- case 'C':
- if (parse_cidr(cfile, cidr) == 0)
- return 0;
- len = 1 + (cidr[0] + 7) / 8;
- dp = cidr;
- break;
- case 'D':
- if (peek_token(NULL, cfile) == TOK_STRING) {
- if (parse_domain_list(cfile, &len,
- (char **)&dp) == 0)
- return 0;
- } else {
- if (parse_hex_octets(cfile, &len, &dp)
- == 0)
- return 0;
- val = rfc1035_as_string(dp, len);
- free(dp);
- dp = strdup(val);
- if (dp == NULL)
- fatal("RFC1035 hex octets");
- len = strlen(dp);
- }
- freedp = 1;
- break;
- default:
- log_warnx("%s: bad format %c in "
- "parse_option_param", log_procname, *fmt);
- skip_to_semi(cfile);
- return 0;
- }
- if (dp != NULL && len > 0) {
- if (hunkix + len > sizeof(hunkbuf)) {
- if (freedp == 1)
- free(dp);
- parse_warn("option data buffer "
- "overflow");
- skip_to_semi(cfile);
- return 0;
- }
- memcpy(&hunkbuf[hunkix], dp, len);
- hunkix += len;
- if (freedp == 1)
- free(dp);
- }
- }
- token = peek_token(NULL, cfile);
- if (*fmt == 'A' && token == ',')
- token = next_token(NULL, cfile);
- } while (*fmt == 'A' && token == ',');
-
- free(options[i].data);
- options[i].data = malloc(hunkix);
- if (options[i].data == NULL)
- fatal("option data");
- memcpy(options[i].data, hunkbuf, hunkix);
- options[i].len = hunkix;
-
- *code = i;
-
- return 1;
-}
-
-int
-parse_reject_statement(FILE *cfile)
-{
- struct in_addr addr;
- struct reject_elem *elem;
-
- if (parse_ip_addr(cfile, &addr) == 0)
- return 0;
-
- TAILQ_FOREACH(elem, &config->reject_list, next) {
- if (elem->addr.s_addr == addr.s_addr)
- return 1;
- }
-
- elem = malloc(sizeof(*elem));
- if (elem == NULL)
- fatal("reject address");
- elem->addr = addr;
- TAILQ_INSERT_TAIL(&config->reject_list, elem, next);
-
- return 1;
-}
-
-void
-apply_actions(uint8_t *actions)
-{
- int i;
-
- for (i = 0; i < DHO_END; i++) {
- switch (actions[i]) {
- case ACTION_IGNORE:
- config->default_actions[i] = ACTION_IGNORE;
- free(config->defaults[i].data);
- config->defaults[i].data = NULL;
- config->defaults[i].len = 0;
- break;
- default:
- break;
- }
- }
-}
-
-void
-set_default_client_identifier(struct ether_addr *hwaddr)
-{
- struct option_data *opt;
-
- /*
- * Check both len && data so
- *
- * send dhcp-client-identifier "";
- *
- * can be used to suppress sending the default client
- * identifier.
- */
- opt = &config->send_options[DHO_DHCP_CLIENT_IDENTIFIER];
- if (opt->len == 0 && opt->data == NULL) {
- opt->data = calloc(1, ETHER_ADDR_LEN + 1);
- if (opt->data == NULL)
- fatal("default client identifier");
- opt->data[0] = HTYPE_ETHER;
- memcpy(&opt->data[1], hwaddr->ether_addr_octet,
- ETHER_ADDR_LEN);
- opt->len = ETHER_ADDR_LEN + 1;
- }
-}
-
-void
-set_default_hostname(void)
-{
- char hn[HOST_NAME_MAX + 1], *p;
- struct option_data *opt;
- int rslt;
-
- /*
- * Check both len && data so
- *
- * send host-name "";
- *
- * can be used to suppress sending the default host
- * name.
- */
- opt = &config->send_options[DHO_HOST_NAME];
- if (opt->len == 0 && opt->data == NULL) {
- rslt = gethostname(hn, sizeof(hn));
- if (rslt == -1) {
- log_warn("host-name");
- return;
- }
- p = strchr(hn, '.');
- if (p != NULL)
- *p = '\0';
- opt->data = strdup(hn);
- if (opt->data == NULL)
- fatal("default host-name");
- opt->len = strlen(opt->data);
- }
-}
+++ /dev/null
-/* $OpenBSD: conflex.c,v 1.50 2019/01/26 23:26:20 krw Exp $ */
-
-/* Lexical scanner for dhclient config file. */
-
-/*
- * Copyright (c) 1995, 1996, 1997 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <arpa/inet.h>
-
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <ctype.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "dhctoken.h"
-#include "log.h"
-
-int lexline;
-int lexchar;
-char *token_line;
-char *tlname;
-
-static char line1[81];
-static char line2[81];
-static char *prev_line;
-static char *cur_line;
-static int lpos;
-static int line;
-static int tlpos;
-static int tline;
-static int token;
-static int ugflag;
-static char *tval;
-static char tokbuf[1500];
-
-static void eol(void);
-static void skip_to_eol(FILE *);
-
-static int get_char(FILE *);
-static int get_token(FILE *);
-static int read_string(FILE *);
-static int read_num_or_name(int, FILE *);
-static int intern(char *, int);
-
-void
-new_parse(char *name)
-{
- /*
- * Initialize all parsing state, as we are starting to parse a
- * new file, 'name'.
- */
-
- memset(line1, 0, sizeof(line1));
- memset(line2, 0, sizeof(line2));
- memset(tokbuf, 0, sizeof(tokbuf));
-
- lpos = line = 1;
- tlpos = tline = token = ugflag = 0;
- tval = NULL;
-
- lexline = lexchar = 0;
- cur_line = line1;
- prev_line = line2;
- token_line = cur_line;
- tlname = name;
-}
-
-/*
- * eol() increments the lexical line.
- *
- * It is split from get_char() because read_num_or_name() does *not*
- * want the lexical line incremented when a '\n' ends the token assembly.
- * Instead, it ungetc()'s the '\n' for the next token parse to deal with.
- * Incrementing the lexical line in that case causes parse_warn() to
- * generate messages that display a blank line instead of the offending
- * token in context.
- *
- * Invoccations of get_char() wanting to increment the lexical line on '\n'
- * must call eol().
- */
-static void
-eol(void)
-{
- if (cur_line == line1) {
- cur_line = line2;
- prev_line = line1;
- } else {
- cur_line = line1;
- prev_line = line2;
- }
- line++;
- lpos = 1;
- cur_line[0] = 0;
-}
-
-static int
-get_char(FILE *cfile)
-{
- int c;
-
- c = getc(cfile);
-
- if (ugflag == 0) {
- if (c != EOF && c != '\n') {
- if ((unsigned int)lpos < sizeof(line1)) {
- cur_line[lpos - 1] = c;
- cur_line[lpos] = 0;
- }
- lpos++;
- }
- } else
- ugflag = 0;
-
- return c;
-}
-
-static int
-get_token(FILE *cfile)
-{
- static char tb[2];
- int c, ttok;
- int l, p, u;
-
- u = ugflag;
-
- for (;;) {
- l = line;
- p = lpos - u;
- u = 0;
-
- c = get_char(cfile);
-
- if (isascii(c) != 0 && isspace(c) != 0) {
- if (c == '\n')
- eol();
- continue;
- }
- if (c == '#') {
- skip_to_eol(cfile);
- continue;
- }
- lexline = l;
- lexchar = p;
- if (c == '"') {
- ttok = read_string(cfile);
- break;
- } else if (c == '-' || (isascii(c) != 0 && isalnum(c) != 0)) {
- ttok = read_num_or_name(c, cfile);
- break;
- } else {
- tb[0] = c;
- tb[1] = 0;
- tval = tb;
- ttok = c;
- break;
- }
- }
- return ttok;
-}
-
-int
-next_token(char **rval, FILE *cfile)
-{
- int rv;
-
- if (token != 0) {
- if (lexline != tline)
- token_line = cur_line;
- lexchar = tlpos;
- lexline = tline;
- rv = token;
- token = 0;
- } else {
- rv = get_token(cfile);
- token_line = cur_line;
- }
- if (rval != 0)
- *rval = tval;
-
- return rv;
-}
-
-int
-peek_token(char **rval, FILE *cfile)
-{
- int x;
-
- if (token == 0) {
- tlpos = lexchar;
- tline = lexline;
- token = get_token(cfile);
- if (lexline != tline)
- token_line = prev_line;
- x = lexchar;
- lexchar = tlpos;
- tlpos = x;
- x = lexline;
- lexline = tline;
- tline = x;
- }
- if (rval != 0)
- *rval = tval;
-
- return token;
-}
-
-static void
-skip_to_eol(FILE *cfile)
-{
- int c;
-
- for (;;) {
- c = get_char(cfile);
- if (c == EOF)
- return;
- if (c == '\n') {
- eol();
- return;
- }
- }
-}
-
-static int
-read_string(FILE *cfile)
-{
- int i, c, bs;
-
- /*
- * Read in characters until an un-escaped '"' is encountered.
- */
- bs = i = 0;
- while ((c = get_char(cfile)) != EOF) {
- if (c == '"' && bs == 0)
- break;
- if (c == '\n')
- eol();
-
- tokbuf[i++] = c;
- if (bs != 0)
- bs = 0;
- else if (c == '\\')
- bs = 1;
-
- if (i == sizeof(tokbuf) - 1)
- break;
- }
- if (bs == 1)
- i--;
-
- if (c == EOF)
- parse_warn("eof in string constant");
- else if (c != '"')
- parse_warn("string constant too long");
-
- tokbuf[i] = '\0';
- tval = tokbuf;
-
- return TOK_STRING;
-}
-
-static int
-read_num_or_name(int c, FILE *cfile)
-{
- unsigned int i, xdigits;
- int rv;
-
- xdigits = (isxdigit(c) != 0) ? 1 : 0;
-
- tokbuf[0] = c;
- for (i = 1; i < sizeof(tokbuf); i++) {
- c = get_char(cfile);
- if (isascii(c) == 0 || (c != '-' && c != '_' &&
- isalnum(c) == 0)) {
- /* N.B.: Do not call eol()! '\n' is put back. */
- ungetc(c, cfile);
- ugflag = 1;
- break;
- }
- if (isxdigit(c) != 0)
- xdigits++;
- tokbuf[i] = c;
- }
- if (i == sizeof(tokbuf)) {
- parse_warn("token larger than internal buffer");
- i--;
- c = tokbuf[i];
- if (isxdigit(c) != 0)
- xdigits--;
- }
- tokbuf[i] = 0;
- tval = tokbuf;
-
- c = (unsigned int)tokbuf[0];
-
- if (c == '-')
- rv = TOK_NUMBER;
- else
- rv = intern(tval, TOK_NUMBER_OR_NAME);
-
- if (rv == TOK_NUMBER_OR_NAME && xdigits != i)
- rv = TOK_NAME;
-
- return rv;
-}
-
-static const struct keywords {
- const char *k_name;
- int k_val;
-} keywords[] = {
- { "append", TOK_APPEND },
- { "backoff-cutoff", TOK_BACKOFF_CUTOFF },
- { "bootp", TOK_BOOTP },
- { "default", TOK_DEFAULT },
- { "epoch", TOK_EPOCH },
- { "expire", TOK_EXPIRE },
- { "filename", TOK_FILENAME },
- { "fixed-address", TOK_FIXED_ADDR },
- { "ignore", TOK_IGNORE },
- { "initial-interval", TOK_INITIAL_INTERVAL },
- { "interface", TOK_INTERFACE },
- { "lease", TOK_LEASE },
- { "link-timeout", TOK_LINK_TIMEOUT },
- { "next-server", TOK_NEXT_SERVER },
- { "option", TOK_OPTION },
- { "prepend", TOK_PREPEND },
- { "rebind", TOK_REBIND },
- { "reboot", TOK_REBOOT },
- { "reject", TOK_REJECT },
- { "renew", TOK_RENEW },
- { "request", TOK_REQUEST },
- { "require", TOK_REQUIRE },
- { "retry", TOK_RETRY },
- { "select-timeout", TOK_SELECT_TIMEOUT },
- { "send", TOK_SEND },
- { "server-name", TOK_SERVER_NAME },
- { "ssid", TOK_SSID },
- { "supersede", TOK_SUPERSEDE },
- { "timeout", TOK_TIMEOUT },
- { "uselease", TOK_USELEASE }
-};
-
-int kw_cmp(const void *k, const void *e);
-
-int
-kw_cmp(const void *k, const void *e)
-{
- return strcasecmp(k, ((const struct keywords *)e)->k_name);
-}
-
-static int
-intern(char *atom, int dfv)
-{
- const struct keywords *p;
-
- p = bsearch(atom, keywords, sizeof(keywords)/sizeof(keywords[0]),
- sizeof(keywords[0]), kw_cmp);
- if (p != NULL)
- return p->k_val;
- return dfv;
-}
+++ /dev/null
-.\" $OpenBSD: dhclient.8,v 1.50 2022/05/16 17:15:16 abieber Exp $
-.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of The Internet Software Consortium nor the names
-.\" of its contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
-.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
-.Dd $Mdocdate: May 16 2022 $
-.Dt DHCLIENT 8
-.Os
-.Sh NAME
-.Nm dhclient
-.Nd Dynamic Host Configuration Protocol (DHCP) client
-.Sh SYNOPSIS
-.Nm
-.Op Fl dnrv
-.Op Fl c Ar file
-.Op Fl i Ar options
-.Ar interface
-.Sh DESCRIPTION
-.Nm
-uses the Dynamic Host Configuration Protocol (DHCP), or its
-predecessor BOOTP, to configure a network interface.
-Information typically provided via DHCP includes
-IPv4 address and subnet mask, default route,
-and domain name server.
-.Pp
-The options are as follows:
-.Bl -tag -width Ds
-.It Fl c Ar file
-Specify an alternate location to
-.Pa /etc/dhclient.conf
-for the configuration file.
-If
-.Ar file
-is the empty string then no configuration file is read.
-.It Fl d
-Do not daemonize.
-If this option is specified,
-.Nm
-will run in the foreground and log to
-.Em stderr .
-.It Fl i Ar options
-.Nm
-will ignore values provided by leases for the options specified.
-This list will supplement ignore statements in
-.Xr dhclient.conf 5 .
-.Ar options
-must be a comma separated list of valid option names.
-.It Fl n
-Configtest mode.
-Only check the configuration file for validity.
-.It Fl r
-Release the current lease back to the server it came from.
-.Nm
-exits after removing the active lease from
-.Pa /var/db/dhclient.leases . Ns Aq Ar IFNAME ,
-deleting the address the lease caused to be added to the interface,
-and sending a DHCPRELEASE packet to the server that supplied the lease.
-.Pp
-If there is no
-.Nm
-controlling the specified interface, or
-.Nm
-has no active lease configured, no action is performed.
-.It Fl v
-Causes
-.Nm
-to show more information about interactions with the DHCP server and what
-network configuration changes are attempted after accepting a lease.
-.Fl v
-is implied if either
-.Fl d
-or
-.Fl n
-is present.
-.El
-.Pp
-The DHCP protocol allows a host to contact a central server which
-maintains a list of IP addresses which may be assigned on one or more
-subnets.
-A DHCP client may request an address from this pool, and
-then use it on a temporary basis for communication on the network.
-The DHCP protocol also provides a mechanism whereby a client can learn
-important details about the network to which it is attached, such as
-the location of a default router, the location of a name server, and
-so on.
-.Pp
-On startup,
-.Nm
-reads
-.Pa /etc/dhclient.conf
-for configuration instructions.
-It then attempts to configure the network interface
-.Ar interface
-with DHCP.
-The special value
-.Dq egress
-may be used instead of a network interface name.
-In this case
-.Nm
-will look for the network interface currently in the interface group
-.Dq egress
-and configure it with DHCP.
-If there is more than one network interface in the egress group,
-.Nm
-will exit with an error.
-.Pp
-When configuring the interface,
-.Nm
-attempts to remove any existing addresses, gateway routes that use
-the interface, and non-permanent
-.Xr arp 8
-entries.
-.Nm
-automatically exits whenever a new
-.Nm
-is run on the same interface.
-.Pp
-Once the interface is configured,
-.Nm
-constructs a
-.Xr resolv.conf 5
-file.
-It does this only if any of the options
-.Cm domain-name ,
-.Cm domain-name-servers ,
-or
-.Cm domain-search
-are present
-(note that these options may be offered by the DHCP server but suppressed by
-.Xr dhclient.conf 5 ) .
-If a resolv.conf is constructed,
-.Nm
-appends any contents of the
-.Pa /etc/resolv.conf.tail
-file, which are read once at start up.
-The constructed resolv.conf is copied into
-.Pa /etc/resolv.conf
-whenever the default route goes out the interface
-.Nm
-is running on.
-.Nm
-monitors the system for changes to the default route and re-checks
-whether it should write its resolv.conf when possible changes are
-detected.
-.Pp
-In order to keep track of leases across system reboots and server
-restarts,
-.Nm
-keeps a list of leases it has been assigned in the
-.Pa /var/db/dhclient.leases . Ns Aq Ar IFNAME
-file.
-.Ar IFNAME
-represents the network interface of the DHCP client
-.Pq e.g. em0 ,
-one for each interface.
-On startup, after reading the
-.Xr dhclient.conf 5
-file,
-.Nm
-reads the leases file to refresh its memory about what leases it has been
-assigned.
-.Pp
-Old leases are kept around in case the DHCP server is unavailable when
-.Nm
-is first invoked (generally during the initial system boot
-process).
-In that event, old leases from the
-.Pa dhclient.leases . Ns Aq Ar IFNAME
-file which have not yet expired are tested, and if they are determined to
-be valid, they are used until either they expire or the DHCP server
-becomes available.
-.Pp
-A mobile host which may sometimes need to access a network on which no
-DHCP server exists may be preloaded with a lease for a fixed
-address on that network.
-When all attempts to contact a DHCP server have failed,
-.Nm
-will try to validate the static lease, and if it
-succeeds, it will use that lease until it is restarted.
-.Pp
-A mobile host may also travel to some networks on which DHCP is not
-available but BOOTP is.
-In that case, it may be advantageous to
-arrange with the network administrator for an entry on the BOOTP
-database, so that the host can boot quickly on that network rather
-than cycling through the list of old leases.
-.Sh FILES
-.Bl -tag -width "/var/db/dhclient.leases.<IFNAME>XXX" -compact
-.It Pa /etc/dhclient.conf
-DHCP client configuration file
-.It Pa /etc/hostname.XXX
-interface-specific configuration files
-.It Pa /var/db/dhclient.leases . Ns Aq Ar IFNAME
-database of acquired leases
-.El
-.Sh SEE ALSO
-.Xr dhclient.conf 5 ,
-.Xr dhclient.leases 5 ,
-.Xr hostname.if 5 ,
-.Xr dhcpd 8 ,
-.Xr dhcrelay 8 ,
-.Xr ifconfig 8
-.Sh STANDARDS
-.Rs
-.%A R. Droms
-.%D October 1993
-.%R RFC 1534
-.%T Interoperation Between DHCP and BOOTP
-.Re
-.Pp
-.Rs
-.%A R. Droms
-.%D March 1997
-.%R RFC 2131
-.%T Dynamic Host Configuration Protocol
-.Re
-.Pp
-.Rs
-.%A S. Alexander
-.%A R. Droms
-.%D March 1997
-.%R RFC 2132
-.%T DHCP Options and BOOTP Vendor Extensions
-.Re
-.Pp
-.Rs
-.%A T. Lemon
-.%A S. Cheshire
-.%D November 2002
-.%R RFC 3396
-.%T Encoding Long Options in the Dynamic Host Configuration Protocol (DHCPv4)
-.Re
-.Pp
-.Rs
-.%A T. Lemon
-.%A S. Cheshire
-.%A B. Volz
-.%D December 2002
-.%R RFC 3442
-.%T The Classless Static Route Option for Dynamic Host Configuration Protocol (DHCP) version 4
-.Re
-.Pp
-.Rs
-.%A N. Swamy
-.%A G. Halwasia
-.%A P. Jhingram
-.%D January 2013
-.%R RFC 6842
-.%T Client Identifier Option in DHCP Server Replies
-.Re
-.Sh AUTHORS
-.An -nosplit
-.Nm
-was written by
-.An Ted Lemon Aq Mt mellon@fugue.com
-and
-.An Elliot Poger Aq Mt elliot@poger.com .
-.Pp
-The current implementation was reworked by
-.An Henning Brauer Aq Mt henning@openbsd.org .
+++ /dev/null
-/* $OpenBSD: dhclient.c,v 1.728 2024/04/28 16:43:42 florian Exp $ */
-
-/*
- * Copyright 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- *
- * This client was substantially modified and enhanced by Elliot Poger
- * for use on Linux while he was working on the MosquitoNet project at
- * Stanford.
- *
- * The current version owes much to Elliot's Linux enhancements, but
- * was substantially reorganized and partially rewritten by Ted Lemon
- * so as to use the same networking framework that the Internet Software
- * Consortium DHCP server uses. Much system-specific configuration code
- * was moved into a shell script so that as support for more operating
- * systems is added, it will not be necessary to port and maintain
- * system-specific configuration code to these operating systems - instead,
- * the shell script can invoke the native tools to accomplish the same
- * purpose.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/uio.h>
-#include <sys/queue.h>
-
-#include <net/if.h>
-#include <net/if_types.h>
-#include <net/if_dl.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <net80211/ieee80211.h>
-#include <net80211/ieee80211_ioctl.h>
-
-#include <arpa/inet.h>
-
-#include <ctype.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <ifaddrs.h>
-#include <imsg.h>
-#include <limits.h>
-#include <paths.h>
-#include <poll.h>
-#include <pwd.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-#include "privsep.h"
-
-char *path_dhclient_conf;
-char *path_lease_db;
-char *log_procname;
-
-int nullfd = -1;
-int cmd_opts;
-int quit;
-
-const struct in_addr inaddr_any = { INADDR_ANY };
-const struct in_addr inaddr_broadcast = { INADDR_BROADCAST };
-
-struct client_config *config;
-struct imsgbuf *unpriv_ibuf;
-
-void usage(void);
-int res_hnok_list(const char *);
-int addressinuse(char *, struct in_addr, char *);
-
-void fork_privchld(struct interface_info *, int, int);
-void get_name(struct interface_info *, int, char *);
-void get_ssid(struct interface_info *, int);
-void get_sockets(struct interface_info *);
-int get_routefd(int);
-void set_iff_up(struct interface_info *, int);
-void set_user(char *);
-int get_ifa_family(char *, int);
-struct ifaddrs *get_link_ifa(const char *, struct ifaddrs *);
-void interface_state(struct interface_info *);
-struct interface_info *initialize_interface(char *, int);
-void tick_msg(const char *, int);
-void rtm_dispatch(struct interface_info *, struct rt_msghdr *);
-
-struct client_lease *apply_defaults(struct client_lease *);
-struct client_lease *clone_lease(struct client_lease *);
-
-void state_reboot(struct interface_info *);
-void state_init(struct interface_info *);
-void state_selecting(struct interface_info *);
-void state_bound(struct interface_info *);
-void state_panic(struct interface_info *);
-
-void set_interval(struct interface_info *, struct timespec *);
-void set_resend_timeout(struct interface_info *, struct timespec *,
- void (*where)(struct interface_info *));
-void set_secs(struct interface_info *, struct timespec *);
-
-void send_discover(struct interface_info *);
-void send_request(struct interface_info *);
-void send_decline(struct interface_info *);
-void send_release(struct interface_info *);
-
-void process_offer(struct interface_info *, struct option_data *,
- const char *);
-void bind_lease(struct interface_info *);
-
-void make_discover(struct interface_info *, struct client_lease *);
-void make_request(struct interface_info *, struct client_lease *);
-void make_decline(struct interface_info *, struct client_lease *);
-void make_release(struct interface_info *, struct client_lease *);
-
-void release_lease(struct interface_info *);
-void propose_release(struct interface_info *);
-
-void write_lease_db(struct interface_info *);
-char *lease_as_string(char *, struct client_lease *);
-struct proposal *lease_as_proposal(struct client_lease *);
-struct unwind_info *lease_as_unwind_info(struct client_lease *);
-void append_statement(char *, size_t, char *, char *);
-time_t lease_expiry(struct client_lease *);
-time_t lease_renewal(struct client_lease *);
-time_t lease_rebind(struct client_lease *);
-void get_lease_timeouts(struct interface_info *, struct client_lease *);
-
-struct client_lease *packet_to_lease(struct interface_info *,
- struct option_data *);
-void go_daemon(void);
-int rdaemon(int);
-int take_charge(struct interface_info *, int, char *);
-int autoconf(struct interface_info *);
-struct client_lease *get_recorded_lease(struct interface_info *);
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-#define TICK_WAIT 0
-#define TICK_SUCCESS 1
-#define TICK_DAEMON 2
-
-static FILE *leaseFile;
-
-int
-get_ifa_family(char *cp, int n)
-{
- struct sockaddr *sa;
- unsigned int i;
-
- for (i = 1; i; i <<= 1) {
- if ((i & n) != 0) {
- sa = (struct sockaddr *)cp;
- if (i == RTA_IFA)
- return sa->sa_family;
- ADVANCE(cp, sa);
- }
- }
-
- return AF_UNSPEC;
-}
-
-struct ifaddrs *
-get_link_ifa(const char *name, struct ifaddrs *ifap)
-{
- struct ifaddrs *ifa;
- struct sockaddr_dl *sdl;
-
- for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) {
- if (strcmp(name, ifa->ifa_name) == 0 &&
- (ifa->ifa_flags & IFF_LOOPBACK) == 0 &&
- (ifa->ifa_flags & IFF_POINTOPOINT) == 0 &&
- ifa->ifa_data != NULL && /* NULL shouldn't be possible. */
- ifa->ifa_addr != NULL &&
- ifa->ifa_addr->sa_family == AF_LINK) {
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- if (sdl->sdl_alen == ETHER_ADDR_LEN &&
- (sdl->sdl_type == IFT_ETHER ||
- sdl->sdl_type == IFT_CARP))
- break;
- }
- }
-
- if (ifa == NULL)
- fatal("get_link_ifa()");
-
- return ifa;
-}
-
-void
-interface_state(struct interface_info *ifi)
-{
- struct ifaddrs *ifap, *ifa;
- struct if_data *ifd;
- struct sockaddr_dl *sdl;
- char *oldlladdr;
- int newlinkup, oldlinkup;
-
- oldlinkup = LINK_STATE_IS_UP(ifi->link_state);
-
- if (getifaddrs(&ifap) == -1)
- fatal("getifaddrs");
-
- ifa = get_link_ifa(ifi->name, ifap);
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- ifd = (struct if_data *)ifa->ifa_data;
-
- if ((ifa->ifa_flags & IFF_UP) == 0 ||
- (ifa->ifa_flags & IFF_RUNNING) == 0) {
- ifi->link_state = LINK_STATE_DOWN;
- } else {
- ifi->link_state = ifd->ifi_link_state;
- ifi->mtu = ifd->ifi_mtu;
- }
-
- newlinkup = LINK_STATE_IS_UP(ifi->link_state);
- if (newlinkup != oldlinkup) {
- log_debug("%s: link %s -> %s", log_procname,
- (oldlinkup != 0) ? "up" : "down",
- (newlinkup != 0) ? "up" : "down");
- tick_msg("link", newlinkup ? TICK_SUCCESS : TICK_WAIT);
- }
-
- if (memcmp(&ifi->hw_address, LLADDR(sdl), ETHER_ADDR_LEN) != 0) {
- if (log_getverbose()) {
- oldlladdr = strdup(ether_ntoa(&ifi->hw_address));
- if (oldlladdr == NULL)
- fatal("oldlladdr");
- log_debug("%s: LLADDR %s -> %s", log_procname,
- oldlladdr,
- ether_ntoa((struct ether_addr *)LLADDR(sdl)));
- free(oldlladdr);
- }
- memcpy(&ifi->hw_address, LLADDR(sdl), ETHER_ADDR_LEN);
- quit = RESTART; /* Even if MTU has changed. */
- }
-
- freeifaddrs(ifap);
-}
-
-struct interface_info *
-initialize_interface(char *name, int noaction)
-{
- struct interface_info *ifi;
- struct ifaddrs *ifap, *ifa;
- struct if_data *ifd;
- struct sockaddr_dl *sdl;
- int ioctlfd;
-
- ifi = calloc(1, sizeof(*ifi));
- if (ifi == NULL)
- fatal("ifi");
-
- ifi->rbuf_max = RT_BUF_SIZE;
- ifi->rbuf = malloc(ifi->rbuf_max);
- if (ifi->rbuf == NULL)
- fatal("rbuf");
-
- if ((ioctlfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- fatal("socket(AF_INET, SOCK_DGRAM)");
-
- get_name(ifi, ioctlfd, name);
- ifi->index = if_nametoindex(ifi->name);
- if (ifi->index == 0)
- fatalx("if_nametoindex(%s) == 0", ifi->name);
-
- if (getifaddrs(&ifap) == -1)
- fatal("getifaddrs()");
-
- ifa = get_link_ifa(ifi->name, ifap);
- sdl = (struct sockaddr_dl *)ifa->ifa_addr;
- ifd = (struct if_data *)ifa->ifa_data;
-
- if ((ifa->ifa_flags & IFF_UP) == 0 ||
- (ifa->ifa_flags & IFF_RUNNING) == 0)
- ifi->link_state = LINK_STATE_DOWN;
- else
- ifi->link_state = ifd->ifi_link_state;
-
- memcpy(ifi->hw_address.ether_addr_octet, LLADDR(sdl), ETHER_ADDR_LEN);
- ifi->rdomain = ifd->ifi_rdomain;
-
- get_sockets(ifi);
- get_ssid(ifi, ioctlfd);
-
- if (noaction == 0 && !LINK_STATE_IS_UP(ifi->link_state))
- set_iff_up(ifi, ioctlfd);
-
- close(ioctlfd);
- freeifaddrs(ifap);
-
- return ifi;
-}
-
-void
-get_name(struct interface_info *ifi, int ioctlfd, char *arg)
-{
- struct ifgroupreq ifgr;
- size_t len;
-
- if (strcmp(arg, "egress") == 0) {
- memset(&ifgr, 0, sizeof(ifgr));
- strlcpy(ifgr.ifgr_name, "egress", sizeof(ifgr.ifgr_name));
- if (ioctl(ioctlfd, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
- fatal("SIOCGIFGMEMB");
- if (ifgr.ifgr_len > sizeof(struct ifg_req))
- fatalx("too many interfaces in group egress");
- if ((ifgr.ifgr_groups = calloc(1, ifgr.ifgr_len)) == NULL)
- fatalx("ifgr_groups");
- if (ioctl(ioctlfd, SIOCGIFGMEMB, (caddr_t)&ifgr) == -1)
- fatal("SIOCGIFGMEMB");
- len = strlcpy(ifi->name, ifgr.ifgr_groups->ifgrq_member,
- IFNAMSIZ);
- free(ifgr.ifgr_groups);
- } else
- len = strlcpy(ifi->name, arg, IFNAMSIZ);
-
- if (len >= IFNAMSIZ)
- fatalx("interface name too long");
-}
-
-void
-get_ssid(struct interface_info *ifi, int ioctlfd)
-{
- struct ieee80211_nwid nwid;
- struct ifreq ifr;
-
- memset(&ifr, 0, sizeof(ifr));
- memset(&nwid, 0, sizeof(nwid));
-
- ifr.ifr_data = (caddr_t)&nwid;
- strlcpy(ifr.ifr_name, ifi->name, sizeof(ifr.ifr_name));
-
- if (ioctl(ioctlfd, SIOCG80211NWID, (caddr_t)&ifr) == 0) {
- memset(ifi->ssid, 0, sizeof(ifi->ssid));
- memcpy(ifi->ssid, nwid.i_nwid, nwid.i_len);
- ifi->ssid_len = nwid.i_len;
- }
-}
-
-void
-set_iff_up(struct interface_info *ifi, int ioctlfd)
-{
- struct ifreq ifr;
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifi->name, sizeof(ifr.ifr_name));
-
- if (ioctl(ioctlfd, SIOCGIFFLAGS, (caddr_t)&ifr) == -1)
- fatal("%s: SIOCGIFFLAGS", ifi->name);
-
- if ((ifr.ifr_flags & IFF_UP) == 0) {
- ifi->link_state = LINK_STATE_DOWN;
- ifr.ifr_flags |= IFF_UP;
- if (ioctl(ioctlfd, SIOCSIFFLAGS, (caddr_t)&ifr) == -1)
- fatal("%s: SIOCSIFFLAGS", ifi->name);
- }
-}
-
-void
-set_user(char *user)
-{
- struct passwd *pw;
-
- pw = getpwnam(user);
- if (pw == NULL)
- fatalx("no such user: %s", user);
-
- if (chroot(pw->pw_dir) == -1)
- fatal("chroot(%s)", pw->pw_dir);
- if (chdir("/") == -1)
- fatal("chdir(\"/\")");
- if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
- fatal("setresgid");
- if (setgroups(1, &pw->pw_gid) == -1)
- fatal("setgroups");
- if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
- fatal("setresuid");
-
- endpwent();
-}
-
-void
-get_sockets(struct interface_info *ifi)
-{
- unsigned char *newp;
- size_t newsize;
-
- ifi->udpfd = get_udp_sock(ifi->rdomain);
- ifi->bpffd = get_bpf_sock(ifi->name);
-
- newsize = configure_bpf_sock(ifi->bpffd);
- if (newsize > ifi->rbuf_max) {
- if ((newp = realloc(ifi->rbuf, newsize)) == NULL)
- fatal("rbuf");
- ifi->rbuf = newp;
- ifi->rbuf_max = newsize;
- }
-}
-
-int
-get_routefd(int rdomain)
-{
- int routefd, rtfilter;
-
- if ((routefd = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1)
- fatal("socket(AF_ROUTE, SOCK_RAW)");
-
- rtfilter = ROUTE_FILTER(RTM_PROPOSAL) | ROUTE_FILTER(RTM_IFINFO) |
- ROUTE_FILTER(RTM_NEWADDR) | ROUTE_FILTER(RTM_DELADDR) |
- ROUTE_FILTER(RTM_IFANNOUNCE) | ROUTE_FILTER(RTM_80211INFO);
-
- if (setsockopt(routefd, AF_ROUTE, ROUTE_MSGFILTER,
- &rtfilter, sizeof(rtfilter)) == -1)
- fatal("setsockopt(ROUTE_MSGFILTER)");
- if (setsockopt(routefd, AF_ROUTE, ROUTE_TABLEFILTER, &rdomain,
- sizeof(rdomain)) == -1)
- fatal("setsockopt(ROUTE_TABLEFILTER)");
-
- return routefd;
-}
-
-void
-routefd_handler(struct interface_info *ifi, int routefd)
-{
- struct rt_msghdr *rtm;
- unsigned char *buf = ifi->rbuf;
- unsigned char *lim, *next;
- ssize_t n;
-
- do {
- n = read(routefd, buf, RT_BUF_SIZE);
- } while (n == -1 && errno == EINTR);
- if (n == -1) {
- log_warn("%s: routing socket", log_procname);
- return;
- }
- if (n == 0)
- fatalx("%s: routing socket closed", log_procname);
-
- lim = buf + n;
- for (next = buf; next < lim && quit == 0; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
- if (lim < next + sizeof(rtm->rtm_msglen) ||
- lim < next + rtm->rtm_msglen)
- fatalx("%s: partial rtm in buffer", log_procname);
-
- if (rtm->rtm_version != RTM_VERSION)
- continue;
-
- rtm_dispatch(ifi, rtm);
- }
-}
-
-void
-rtm_dispatch(struct interface_info *ifi, struct rt_msghdr *rtm)
-{
- struct if_msghdr *ifm;
- struct if_announcemsghdr *ifan;
- struct ifa_msghdr *ifam;
- struct if_ieee80211_data *ifie;
- char *oldssid;
- uint32_t oldmtu;
-
- switch (rtm->rtm_type) {
- case RTM_PROPOSAL:
- if (rtm->rtm_priority == RTP_PROPOSAL_SOLICIT) {
- if (quit == 0 && ifi->active != NULL)
- tell_unwind(ifi->unwind_info, ifi->flags);
- return;
- }
- if (rtm->rtm_index != ifi->index ||
- rtm->rtm_priority != RTP_PROPOSAL_DHCLIENT)
- return;
- if ((rtm->rtm_flags & RTF_PROTO3) != 0) {
- if (rtm->rtm_seq == (int32_t)ifi->xid) {
- ifi->flags |= IFI_IN_CHARGE;
- return;
- } else if ((ifi->flags & IFI_IN_CHARGE) != 0) {
- log_debug("%s: yielding responsibility",
- log_procname);
- quit = TERMINATE;
- }
- } else if ((rtm->rtm_flags & RTF_PROTO2) != 0) {
- release_lease(ifi); /* OK even if we sent it. */
- quit = TERMINATE;
- } else
- return; /* Ignore tell_unwind() proposals. */
- break;
-
- case RTM_DESYNC:
- log_warnx("%s: RTM_DESYNC", log_procname);
- break;
-
- case RTM_IFINFO:
- ifm = (struct if_msghdr *)rtm;
- if (ifm->ifm_index != ifi->index)
- break;
- if ((rtm->rtm_flags & RTF_UP) == 0)
- fatalx("down");
-
- oldmtu = ifi->mtu;
- interface_state(ifi);
- if (oldmtu == ifi->mtu)
- quit = RESTART;
- else
- log_debug("%s: MTU %u -> %u",
- log_procname, oldmtu, ifi->mtu);
- break;
-
- case RTM_80211INFO:
- if (rtm->rtm_index != ifi->index)
- break;
- ifie = &((struct if_ieee80211_msghdr *)rtm)->ifim_ifie;
- if (ifi->ssid_len != ifie->ifie_nwid_len || memcmp(ifi->ssid,
- ifie->ifie_nwid, ifie->ifie_nwid_len) != 0) {
- if (log_getverbose()) {
- oldssid = strdup(pretty_print_string(ifi->ssid,
- ifi->ssid_len, 1));
- if (oldssid == NULL)
- fatal("oldssid");
- log_debug("%s: SSID %s -> %s", log_procname,
- oldssid, pretty_print_string(ifie->ifie_nwid,
- ifie->ifie_nwid_len, 1));
- free(oldssid);
- }
- quit = RESTART;
- }
- break;
-
- case RTM_IFANNOUNCE:
- ifan = (struct if_announcemsghdr *)rtm;
- if (ifan->ifan_what == IFAN_DEPARTURE && ifan->ifan_index ==
- ifi->index)
- fatalx("departed");
- break;
-
- case RTM_NEWADDR:
- case RTM_DELADDR:
- /* Need to check if it is time to write resolv.conf. */
- ifam = (struct ifa_msghdr *)rtm;
- if (get_ifa_family((char *)ifam + ifam->ifam_hdrlen,
- ifam->ifam_addrs) != AF_INET)
- return;
- break;
-
- default:
- break;
- }
-
- /*
- * Responsibility for resolv.conf may have changed hands.
- */
- if (quit == 0 && ifi->active != NULL &&
- (ifi->flags & IFI_IN_CHARGE) != 0 &&
- ifi->state == S_BOUND)
- write_resolv_conf();
-}
-
-int
-main(int argc, char *argv[])
-{
- uint8_t actions[DHO_END];
- struct stat sb;
- struct interface_info *ifi;
- char *ignore_list, *p;
- int fd, socket_fd[2];
- int routefd;
- int ch, i;
-
- if (isatty(STDERR_FILENO) != 0)
- log_init(1, LOG_DEBUG); /* log to stderr until daemonized */
- else
- log_init(0, LOG_DEBUG); /* can't log to stderr */
-
- log_setverbose(0); /* Don't show log_debug() messages. */
-
- if (lstat(_PATH_DHCLIENT_CONF, &sb) == 0)
- path_dhclient_conf = _PATH_DHCLIENT_CONF;
- memset(actions, ACTION_USELEASE, sizeof(actions));
-
- while ((ch = getopt(argc, argv, "c:di:nrv")) != -1) {
- syslog(LOG_ALERT | LOG_CONS,
- "dhclient will go away, so -%c option will not exist", ch);
- switch (ch) {
- case 'c':
- if (strlen(optarg) == 0)
- path_dhclient_conf = NULL;
- else if (lstat(optarg, &sb) == 0)
- path_dhclient_conf = optarg;
- else
- fatal("lstat(%s)", optarg);
- break;
- case 'd':
- cmd_opts |= OPT_FOREGROUND;
- break;
- case 'i':
- syslog(LOG_ALERT | LOG_CONS,
- "dhclient will go away, for -i learn dhcpleased.conf");
- if (strlen(optarg) == 0)
- break;
- ignore_list = strdup(optarg);
- if (ignore_list == NULL)
- fatal("ignore_list");
- for (p = strsep(&ignore_list, ", "); p != NULL;
- p = strsep(&ignore_list, ", ")) {
- if (*p == '\0')
- continue;
- i = name_to_code(p);
- if (i == DHO_END)
- fatalx("invalid option name: '%s'", p);
- actions[i] = ACTION_IGNORE;
- }
- free(ignore_list);
- break;
- case 'n':
- cmd_opts |= OPT_NOACTION;
- break;
- case 'r':
- cmd_opts |= OPT_RELEASE;
- break;
- case 'v':
- cmd_opts |= OPT_VERBOSE;
- break;
- default:
- usage();
- }
- }
-
- argc -= optind;
- argv += optind;
-
- if (argc != 1)
- usage();
-
- syslog(LOG_ALERT | LOG_CONS,
- "dhclient will go away, stop using it");
-
- execl("/sbin/ifconfig", "ifconfig", argv[0], "inet", "autoconf", NULL);
-
- if ((cmd_opts & (OPT_FOREGROUND | OPT_NOACTION)) != 0)
- cmd_opts |= OPT_VERBOSE;
-
- if ((cmd_opts & OPT_VERBOSE) != 0)
- log_setverbose(1); /* Show log_debug() messages. */
-
- ifi = initialize_interface(argv[0], cmd_opts & OPT_NOACTION);
-
- log_procname = strdup(ifi->name);
- if (log_procname == NULL)
- fatal("log_procname");
- setproctitle("%s", log_procname);
- log_procinit(log_procname);
-
- tzset();
-
- if (setrtable(ifi->rdomain) == -1)
- fatal("setrtable(%u)", ifi->rdomain);
-
- if ((cmd_opts & OPT_RELEASE) != 0) {
- if ((cmd_opts & OPT_NOACTION) == 0)
- propose_release(ifi);
- exit(0);
- }
-
- signal(SIGPIPE, SIG_IGN); /* Don't wait for go_daemon()! */
-
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0,
- socket_fd) == -1)
- fatal("socketpair");
-
- if ((nullfd = open(_PATH_DEVNULL, O_RDWR)) == -1)
- fatal("open(%s)", _PATH_DEVNULL);
-
- fork_privchld(ifi, socket_fd[0], socket_fd[1]);
-
- close(socket_fd[0]);
- if ((unpriv_ibuf = malloc(sizeof(*unpriv_ibuf))) == NULL)
- fatal("unpriv_ibuf");
- imsg_init(unpriv_ibuf, socket_fd[1]);
-
- read_conf(ifi->name, actions, &ifi->hw_address);
- if ((cmd_opts & OPT_NOACTION) != 0)
- return 0;
-
- if (asprintf(&path_lease_db, "%s.%s", _PATH_LEASE_DB, ifi->name) == -1)
- fatal("path_lease_db");
-
- routefd = get_routefd(ifi->rdomain);
- fd = take_charge(ifi, routefd, path_lease_db); /* Kill other dhclients. */
- if (autoconf(ifi)) {
- /* dhcpleased has been notified to request a new lease. */
- return 0;
- }
- if (fd != -1)
- read_lease_db(&ifi->lease_db);
-
- if ((leaseFile = fopen(path_lease_db, "w")) == NULL)
- log_warn("%s: fopen(%s)", log_procname, path_lease_db);
- write_lease_db(ifi);
-
- set_user("_dhcp");
-
- if ((cmd_opts & OPT_FOREGROUND) == 0) {
- if (pledge("stdio inet dns route proc", NULL) == -1)
- fatal("pledge");
- } else {
- if (pledge("stdio inet dns route", NULL) == -1)
- fatal("pledge");
- }
-
- tick_msg("link", LINK_STATE_IS_UP(ifi->link_state) ? TICK_SUCCESS :
- TICK_WAIT);
- quit = RESTART;
- dispatch(ifi, routefd);
-
- return 0;
-}
-
-void
-usage(void)
-{
- extern char *__progname;
-
- fprintf(stderr,
- "usage: %s [-dnrv] [-c file] [-i options] "
- "interface\n", __progname);
- exit(1);
-}
-
-void
-state_preboot(struct interface_info *ifi)
-{
- interface_state(ifi);
- if (quit != 0)
- return;
-
- if (LINK_STATE_IS_UP(ifi->link_state)) {
- tick_msg("link", TICK_SUCCESS);
- ifi->state = S_REBOOTING;
- state_reboot(ifi);
- } else {
- tick_msg("link", TICK_WAIT);
- set_timeout(ifi, 1, state_preboot);
- }
-}
-
-/*
- * Called when the interface link becomes active.
- */
-void
-state_reboot(struct interface_info *ifi)
-{
- const struct timespec reboot_intvl = {config->reboot_interval, 0};
- struct client_lease *lease;
-
- cancel_timeout(ifi);
-
- /*
- * If there is no recorded lease or the lease is BOOTP then
- * go straight to INIT and try to DISCOVER a new lease.
- */
- ifi->active = get_recorded_lease(ifi);
- if (ifi->active == NULL || BOOTP_LEASE(ifi->active)) {
- ifi->state = S_INIT;
- state_init(ifi);
- return;
- }
- lease = apply_defaults(ifi->active);
- get_lease_timeouts(ifi, lease);
- free_client_lease(lease);
-
- ifi->xid = arc4random();
- make_request(ifi, ifi->active);
-
- ifi->destination.s_addr = INADDR_BROADCAST;
- clock_gettime(CLOCK_MONOTONIC, &ifi->first_sending);
- timespecadd(&ifi->first_sending, &reboot_intvl, &ifi->reboot_timeout);
- ifi->interval = 0;
-
- send_request(ifi);
-}
-
-/*
- * Called when a lease has completely expired and we've been unable to
- * renew it.
- */
-void
-state_init(struct interface_info *ifi)
-{
- const struct timespec offer_intvl = {config->offer_interval, 0};
-
- ifi->xid = arc4random();
- make_discover(ifi, ifi->active);
-
- ifi->destination.s_addr = INADDR_BROADCAST;
- ifi->state = S_SELECTING;
- clock_gettime(CLOCK_MONOTONIC, &ifi->first_sending);
- timespecadd(&ifi->first_sending, &offer_intvl, &ifi->offer_timeout);
- ifi->select_timeout = ifi->offer_timeout;
- ifi->interval = 0;
-
- send_discover(ifi);
-}
-
-/*
- * Called when one or more DHCPOFFER packets have been received and a
- * configurable period of time has passed.
- */
-void
-state_selecting(struct interface_info *ifi)
-{
- cancel_timeout(ifi);
-
- if (ifi->offer == NULL) {
- state_panic(ifi);
- return;
- }
-
- ifi->state = S_REQUESTING;
-
- /* If it was a BOOTREPLY, we can just take the lease right now. */
- if (BOOTP_LEASE(ifi->offer)) {
- bind_lease(ifi);
- return;
- }
-
- ifi->destination.s_addr = INADDR_BROADCAST;
- clock_gettime(CLOCK_MONOTONIC, &ifi->first_sending);
- ifi->interval = 0;
-
- /*
- * Make a DHCPREQUEST packet from the lease we picked. Keep
- * the current xid, as all offers should have had the same
- * one.
- */
- make_request(ifi, ifi->offer);
-
- /* Toss the lease we picked - we'll get it back in a DHCPACK. */
- free_client_lease(ifi->offer);
- ifi->offer = NULL;
- free(ifi->offer_src);
- ifi->offer_src = NULL;
-
- send_request(ifi);
-}
-
-void
-dhcpoffer(struct interface_info *ifi, struct option_data *options,
- const char *src)
-{
- if (ifi->state != S_SELECTING) {
- log_debug("%s: unexpected DHCPOFFER from %s - state #%d",
- log_procname, src, ifi->state);
- return;
- }
-
- log_debug("%s: DHCPOFFER from %s", log_procname, src);
- process_offer(ifi, options, src);
-}
-
-void
-bootreply(struct interface_info *ifi, struct option_data *options,
- const char *src)
-{
- if (ifi->state != S_SELECTING) {
- log_debug("%s: unexpected BOOTREPLY from %s - state #%d",
- log_procname, src, ifi->state);
- return;
- }
-
- log_debug("%s: BOOTREPLY from %s", log_procname, src);
- process_offer(ifi, options, src);
-}
-
-void
-process_offer(struct interface_info *ifi, struct option_data *options,
- const char *src)
-{
- const struct timespec select_intvl = {config->select_interval, 0};
- struct timespec now;
- struct client_lease *lease;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- lease = packet_to_lease(ifi, options);
- if (lease != NULL) {
- if (ifi->offer == NULL) {
- ifi->offer = lease;
- free(ifi->offer_src);
- ifi->offer_src = strdup(src); /* NULL is OK */
- timespecadd(&now, &select_intvl, &ifi->select_timeout);
- if (timespeccmp(&ifi->select_timeout,
- &ifi->offer_timeout, >))
- ifi->select_timeout = ifi->offer_timeout;
- } else if (lease->address.s_addr ==
- ifi->offer->address.s_addr) {
- /* Decline duplicate offers. */
- } else if (lease->address.s_addr ==
- ifi->requested_address.s_addr) {
- free_client_lease(ifi->offer);
- ifi->offer = lease;
- free(ifi->offer_src);
- ifi->offer_src = strdup(src); /* NULL is OK */
- }
-
- if (ifi->offer != lease) {
- make_decline(ifi, lease);
- send_decline(ifi);
- free_client_lease(lease);
- } else if (ifi->offer->address.s_addr ==
- ifi->requested_address.s_addr) {
- ifi->select_timeout = now;
- }
- }
-
- if (timespeccmp(&now, &ifi->select_timeout, >=))
- state_selecting(ifi);
- else {
- ifi->timeout = ifi->select_timeout;
- ifi->timeout_func = state_selecting;
- }
-}
-
-void
-dhcpack(struct interface_info *ifi, struct option_data *options,
- const char *src)
-{
- struct client_lease *lease;
-
- if (ifi->state != S_REBOOTING &&
- ifi->state != S_REQUESTING &&
- ifi->state != S_RENEWING) {
- log_debug("%s: unexpected DHCPACK from %s - state #%d",
- log_procname, src, ifi->state);
- return;
- }
-
- log_debug("%s: DHCPACK", log_procname);
-
- lease = packet_to_lease(ifi, options);
- if (lease == NULL) {
- ifi->state = S_INIT;
- state_init(ifi);
- return;
- }
-
- ifi->offer = lease;
- ifi->offer_src = strdup(src); /* NULL is OK */
- memcpy(ifi->offer->ssid, ifi->ssid, sizeof(ifi->offer->ssid));
- ifi->offer->ssid_len = ifi->ssid_len;
-
- /* Stop resending DHCPREQUEST. */
- cancel_timeout(ifi);
-
- bind_lease(ifi);
-}
-
-void
-dhcpnak(struct interface_info *ifi, const char *src)
-{
- struct client_lease *ll, *pl;
-
- if (ifi->state != S_REBOOTING &&
- ifi->state != S_REQUESTING &&
- ifi->state != S_RENEWING) {
- log_debug("%s: unexpected DHCPNAK from %s - state #%d",
- log_procname, src, ifi->state);
- return;
- }
-
- log_debug("%s: DHCPNAK", log_procname);
-
- /* Remove the NAK'd address from the database. */
- TAILQ_FOREACH_SAFE(ll, &ifi->lease_db, next, pl) {
- if (ifi->ssid_len == ll->ssid_len &&
- memcmp(ifi->ssid, ll->ssid, ll->ssid_len) == 0 &&
- ll->address.s_addr == ifi->requested_address.s_addr) {
- if (ll == ifi->active) {
- tell_unwind(NULL, ifi->flags);
- free(ifi->unwind_info);
- ifi->unwind_info = NULL;
- revoke_proposal(ifi->configured);
- free(ifi->configured);
- ifi->configured = NULL;
- ifi->active = NULL;
- }
- TAILQ_REMOVE(&ifi->lease_db, ll, next);
- free_client_lease(ll);
- write_lease_db(ifi);
- }
- }
-
- /* Stop sending DHCPREQUEST packets. */
- cancel_timeout(ifi);
-
- ifi->state = S_INIT;
- state_init(ifi);
-}
-
-void
-bind_lease(struct interface_info *ifi)
-{
- struct timespec now;
- struct client_lease *lease, *pl, *ll;
- struct proposal *effective_proposal = NULL;
- struct unwind_info *unwind_info;
- char *msg = NULL;
- int rslt, seen;
-
- tick_msg("lease", TICK_SUCCESS);
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- lease = apply_defaults(ifi->offer);
- get_lease_timeouts(ifi, lease);
-
- /* Replace the old active lease with the accepted offer. */
- ifi->active = ifi->offer;
- ifi->offer = NULL;
-
- /*
- * Supply unwind with updated info.
- */
- unwind_info = lease_as_unwind_info(ifi->active);
- if (ifi->unwind_info == NULL && unwind_info != NULL) {
- ifi->unwind_info = unwind_info;
- tell_unwind(ifi->unwind_info, ifi->flags);
- } else if (ifi->unwind_info != NULL && unwind_info == NULL) {
- tell_unwind(NULL, ifi->flags);
- free(ifi->unwind_info);
- ifi->unwind_info = NULL;
- } else if (ifi->unwind_info != NULL && unwind_info != NULL) {
- if (memcmp(ifi->unwind_info, unwind_info,
- sizeof(*ifi->unwind_info)) != 0) {
- tell_unwind(NULL, ifi->flags);
- free(ifi->unwind_info);
- ifi->unwind_info = unwind_info;
- tell_unwind(ifi->unwind_info, ifi->flags);
- }
- }
-
- effective_proposal = lease_as_proposal(lease);
- if (ifi->configured != NULL) {
- if (memcmp(ifi->configured, effective_proposal,
- sizeof(*ifi->configured)) == 0)
- goto newlease;
- }
- free(ifi->configured);
- ifi->configured = effective_proposal;
- effective_proposal = NULL;
-
- propose(ifi->configured);
- rslt = asprintf(&msg, "%s lease accepted from %s",
- inet_ntoa(ifi->active->address),
- (ifi->offer_src == NULL) ? "<unknown>" : ifi->offer_src);
- if (rslt == -1)
- fatal("bind msg");
-
-newlease:
- seen = 0;
- TAILQ_FOREACH_SAFE(ll, &ifi->lease_db, next, pl) {
- if (ifi->ssid_len != ll->ssid_len ||
- memcmp(ifi->ssid, ll->ssid, ll->ssid_len) != 0)
- continue;
- if (ifi->active == ll)
- seen = 1;
- else if (ll->address.s_addr == ifi->active->address.s_addr) {
- TAILQ_REMOVE(&ifi->lease_db, ll, next);
- free_client_lease(ll);
- }
- }
- if (seen == 0) {
- if (ifi->active->epoch == 0)
- time(&ifi->active->epoch);
- TAILQ_INSERT_HEAD(&ifi->lease_db, ifi->active, next);
- }
-
- /*
- * Write out updated information before going daemon.
- *
- * Some scripts (e.g. the installer in autoinstall mode) assume that
- * the bind process is complete and all related information is in
- * place when dhclient(8) goes daemon.
- */
- write_lease_db(ifi);
-
- free_client_lease(lease);
- free(effective_proposal);
- free(ifi->offer_src);
- ifi->offer_src = NULL;
-
- if (msg != NULL) {
- if ((cmd_opts & OPT_FOREGROUND) != 0) {
- /* log msg on console only. */
- ;
- } else if (isatty(STDERR_FILENO) != 0) {
- /*
- * log msg to console and then go_daemon() so it is
- * logged again, this time to /var/log/daemon.
- */
- log_info("%s: %s", log_procname, msg);
- go_daemon();
- }
- log_info("%s: %s", log_procname, msg);
- free(msg);
- }
-
- ifi->state = S_BOUND;
- go_daemon();
-
- /*
- * Set timeout to start the renewal process.
- *
- * If the renewal time is in the past, the lease is from the
- * leaseDB. Rather than immediately trying to contact a server,
- * pause the configured time between attempts.
- */
- if (timespeccmp(&now, &ifi->renew, >=))
- set_timeout(ifi, config->retry_interval, state_bound);
- else {
- ifi->timeout = ifi->renew;
- ifi->timeout_func = state_bound;
- }
-}
-
-/*
- * Called when we've successfully bound to a particular lease, but the renewal
- * time on that lease has expired. We are expected to unicast a DHCPREQUEST to
- * the server that gave us our original lease.
- */
-void
-state_bound(struct interface_info *ifi)
-{
- struct option_data *opt;
- struct in_addr *dest;
-
- ifi->xid = arc4random();
- make_request(ifi, ifi->active);
-
- dest = &ifi->destination;
- opt = &ifi->active->options[DHO_DHCP_SERVER_IDENTIFIER];
-
- if (opt->len == sizeof(*dest))
- dest->s_addr = ((struct in_addr *)opt->data)->s_addr;
- else
- dest->s_addr = INADDR_BROADCAST;
-
- clock_gettime(CLOCK_MONOTONIC, &ifi->first_sending);
- ifi->interval = 0;
- ifi->state = S_RENEWING;
-
- send_request(ifi);
-}
-
-int
-addressinuse(char *name, struct in_addr address, char *ifname)
-{
- struct ifaddrs *ifap, *ifa;
- struct sockaddr_in *sin;
- int used = 0;
-
- if (getifaddrs(&ifap) != 0) {
- log_warn("%s: getifaddrs", log_procname);
- return 0;
- }
-
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if (ifa->ifa_addr == NULL ||
- ifa->ifa_addr->sa_family != AF_INET)
- continue;
-
- sin = (struct sockaddr_in *)ifa->ifa_addr;
- if (memcmp(&address, &sin->sin_addr, sizeof(address)) == 0) {
- strlcpy(ifname, ifa->ifa_name, IF_NAMESIZE);
- used = 1;
- if (strncmp(ifname, name, IF_NAMESIZE) != 0)
- break;
- }
- }
-
- freeifaddrs(ifap);
- return used;
-}
-
-/*
- * Allocate a client_lease structure and initialize it from the
- * parameters in the received packet.
- *
- * Return NULL and decline the lease if a valid lease cannot be
- * constructed.
- */
-struct client_lease *
-packet_to_lease(struct interface_info *ifi, struct option_data *options)
-{
- char ifname[IF_NAMESIZE];
- struct dhcp_packet *packet = &ifi->recv_packet;
- struct client_lease *lease;
- char *pretty, *name;
- int i;
-
- lease = calloc(1, sizeof(*lease));
- if (lease == NULL) {
- log_warn("%s: lease", log_procname);
- return NULL; /* Can't even DECLINE. */
- }
-
- /* Copy the lease addresses. */
- lease->address.s_addr = packet->yiaddr.s_addr;
- lease->next_server.s_addr = packet->siaddr.s_addr;
-
- /* Copy the lease options. */
- for (i = 0; i < DHO_COUNT; i++) {
- if (options[i].len == 0)
- continue;
- name = code_to_name(i);
- if (i == DHO_DOMAIN_SEARCH) {
- /* Replace RFC 1035 data with a string. */
- pretty = rfc1035_as_string(options[i].data,
- options[i].len);
- free(options[i].data);
- options[i].data = strdup(pretty);
- if (options[i].data == NULL)
- fatal("RFC1035 string");
- options[i].len = strlen(options[i].data);
- } else
- pretty = pretty_print_option(i, &options[i], 0);
- if (strlen(pretty) == 0)
- continue;
- switch (i) {
- case DHO_DOMAIN_SEARCH:
- case DHO_DOMAIN_NAME:
- /*
- * Allow deviant but historically blessed
- * practice of supplying multiple domain names
- * with DHO_DOMAIN_NAME. Thus allowing multiple
- * entries in the resolv.conf 'search' statement.
- */
- if (res_hnok_list(pretty) == 0) {
- log_debug("%s: invalid host name in %s",
- log_procname, name);
- continue;
- }
- break;
- case DHO_HOST_NAME:
- case DHO_NIS_DOMAIN:
- if (res_hnok(pretty) == 0) {
- log_debug("%s: invalid host name in %s",
- log_procname, name);
- continue;
- }
- break;
- default:
- break;
- }
- lease->options[i] = options[i];
- options[i].data = NULL;
- options[i].len = 0;
- }
-
- /*
- * If this lease doesn't supply a required parameter, decline it.
- */
- for (i = 0; i < config->required_option_count; i++) {
- if (lease->options[config->required_options[i]].len == 0) {
- name = code_to_name(config->required_options[i]);
- log_warnx("%s: %s required but missing", log_procname,
- name);
- goto decline;
- }
- }
-
- /*
- * If this lease is trying to sell us an address we are already
- * using, decline it.
- */
- memset(ifname, 0, sizeof(ifname));
- if (addressinuse(ifi->name, lease->address, ifname) != 0 &&
- strncmp(ifname, ifi->name, IF_NAMESIZE) != 0) {
- log_warnx("%s: %s already configured on %s", log_procname,
- inet_ntoa(lease->address), ifname);
- goto decline;
- }
-
- /* If the server name was filled out, copy it. */
- if ((lease->options[DHO_DHCP_OPTION_OVERLOAD].len == 0 ||
- (lease->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) == 0) &&
- packet->sname[0]) {
- lease->server_name = calloc(1, DHCP_SNAME_LEN + 1);
- if (lease->server_name == NULL) {
- log_warn("%s: SNAME", log_procname);
- goto decline;
- }
- memcpy(lease->server_name, packet->sname, DHCP_SNAME_LEN);
- if (res_hnok(lease->server_name) == 0) {
- log_debug("%s: invalid host name in SNAME ignored",
- log_procname);
- free(lease->server_name);
- lease->server_name = NULL;
- }
- }
-
- /* If the file name was filled out, copy it. */
- if ((lease->options[DHO_DHCP_OPTION_OVERLOAD].len == 0 ||
- (lease->options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) == 0) &&
- packet->file[0]) {
- /* Don't count on the NUL terminator. */
- lease->filename = malloc(DHCP_FILE_LEN + 1);
- if (lease->filename == NULL) {
- log_warn("%s: filename", log_procname);
- goto decline;
- }
- memcpy(lease->filename, packet->file, DHCP_FILE_LEN);
- lease->filename[DHCP_FILE_LEN] = '\0';
- }
-
- /*
- * Record the client identifier used to obtain the lease. We already
- * checked that the packet client identifier is absent (RFC 2131) or
- * matches what we sent (RFC 6842),
- */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- if (lease->options[i].len == 0 && config->send_options[i].len != 0) {
- lease->options[i].len = config->send_options[i].len;
- lease->options[i].data = malloc(lease->options[i].len);
- if (lease->options[i].data == NULL)
- fatal("lease client-identifier");
- memcpy(lease->options[i].data, config->send_options[i].data,
- lease->options[i].len);
- }
-
- time(&lease->epoch);
- return lease;
-
-decline:
- make_decline(ifi, lease);
- send_decline(ifi);
- free_client_lease(lease);
- return NULL;
-}
-
-void
-set_interval(struct interface_info *ifi, struct timespec *now)
-{
- struct timespec interval;
-
- if (timespeccmp(now, &ifi->timeout, >))
- ifi->interval = 1;
- else {
- timespecsub(&ifi->timeout, now, &interval);
- if (interval.tv_sec == 0 || interval.tv_nsec > 500000000LL)
- interval.tv_sec++;
- ifi->interval = interval.tv_sec;
- }
-}
-
-void
-set_resend_timeout(struct interface_info *ifi, struct timespec *now,
- void (*where)(struct interface_info *))
-{
- const struct timespec reboot_intvl = {config->reboot_interval, 0};
- const struct timespec initial_intvl = {config->initial_interval, 0};
- const struct timespec cutoff_intvl = {config->backoff_cutoff, 0};
- const struct timespec onesecond = {1, 0};
- struct timespec interval, when;
-
- if (timespeccmp(now, &ifi->link_timeout, <))
- interval = onesecond;
- else if (ifi->interval == 0) {
- if (ifi->state == S_REBOOTING)
- interval = reboot_intvl;
- else
- interval = initial_intvl;
- } else {
- timespecclear(&interval);
- interval.tv_sec = ifi->interval + arc4random_uniform(2 *
- ifi->interval);
- }
- if (timespeccmp(&interval, &onesecond, <))
- interval = onesecond;
- else if (timespeccmp(&interval, &cutoff_intvl, >))
- interval = cutoff_intvl;
-
- timespecadd(now, &interval, &when);
- switch (ifi->state) {
- case S_REBOOTING:
- case S_RENEWING:
- if (timespeccmp(&when, &ifi->expiry, >))
- when = ifi->expiry;
- break;
- case S_SELECTING:
- if (timespeccmp(&when, &ifi->select_timeout, >))
- when = ifi->select_timeout;
- break;
- case S_REQUESTING:
- if (timespeccmp(&when, &ifi->offer_timeout, >))
- when = ifi->offer_timeout;
- break;
- default:
- break;
- }
-
- ifi->timeout = when;
- ifi->timeout_func = where;
-}
-
-void
-set_secs(struct interface_info *ifi, struct timespec *now)
-{
- struct timespec interval;
-
- if (ifi->state != S_REQUESTING) {
- /* Update the number of seconds since we started sending. */
- timespecsub(now, &ifi->first_sending, &interval);
- if (interval.tv_nsec > 500000000LL)
- interval.tv_sec++;
- if (interval.tv_sec > UINT16_MAX)
- ifi->secs = UINT16_MAX;
- else
- ifi->secs = interval.tv_sec;
- }
-
- ifi->sent_packet.secs = htons(ifi->secs);
-}
-
-/*
- * Send out a DHCPDISCOVER packet, and set a timeout to send out another
- * one after the right interval has expired. If we don't get an offer by
- * the time we reach the panic interval, call the panic function.
- */
-void
-send_discover(struct interface_info *ifi)
-{
- struct timespec now;
- ssize_t rslt;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (timespeccmp(&now, &ifi->offer_timeout, >=)) {
- state_panic(ifi);
- return;
- }
-
- set_resend_timeout(ifi, &now, send_discover);
- set_interval(ifi, &now);
- set_secs(ifi, &now);
-
- rslt = send_packet(ifi, inaddr_any, inaddr_broadcast, "DHCPDISCOVER");
- if (rslt != -1)
- log_debug("%s: DHCPDISCOVER %s", log_procname,
- (ifi->requested_address.s_addr == INADDR_ANY) ? "" :
- inet_ntoa(ifi->requested_address));
-
- tick_msg("lease", TICK_WAIT);
-}
-
-/*
- * Called if we haven't received any offers in a preset amount of time. When
- * this happens, we try to use existing leases that haven't yet expired.
- *
- * If LINK_STATE_UNKNOWN, do NOT use recorded leases.
- */
-void
-state_panic(struct interface_info *ifi)
-{
- log_debug("%s: no acceptable DHCPOFFERS received", log_procname);
-
- if (ifi->link_state >= LINK_STATE_UP) {
- ifi->offer = get_recorded_lease(ifi);
- if (ifi->offer != NULL) {
- ifi->state = S_REQUESTING;
- ifi->offer_src = strdup(path_lease_db); /* NULL is OK. */
- bind_lease(ifi);
- return;
- }
- }
-
- /*
- * No leases were available, or what was available didn't work
- */
- log_debug("%s: no working leases in persistent database - sleeping",
- log_procname);
- ifi->state = S_INIT;
- set_timeout(ifi, config->retry_interval, state_init);
- tick_msg("lease", TICK_DAEMON);
-}
-
-void
-send_request(struct interface_info *ifi)
-{
- struct sockaddr_in destination;
- struct in_addr from;
- struct timespec now;
- ssize_t rslt;
- char *addr;
-
- cancel_timeout(ifi);
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- switch (ifi->state) {
- case S_REBOOTING:
- if (timespeccmp(&now, &ifi->reboot_timeout, >=))
- ifi->state = S_INIT;
- else {
- destination.sin_addr.s_addr = INADDR_BROADCAST;
- if (ifi->active == NULL)
- from.s_addr = INADDR_ANY;
- else
- from.s_addr = ifi->active->address.s_addr;
- }
- break;
- case S_RENEWING:
- if (timespeccmp(&now, &ifi->expiry, >=))
- ifi->state = S_INIT;
- else {
- if (timespeccmp(&now, &ifi->rebind, >=))
- destination.sin_addr.s_addr = INADDR_BROADCAST;
- else
- destination.sin_addr.s_addr = ifi->destination.s_addr;
- if (ifi->active == NULL)
- from.s_addr = INADDR_ANY;
- else
- from.s_addr = ifi->active->address.s_addr;
- }
- break;
- case S_REQUESTING:
- if (timespeccmp(&now, &ifi->offer_timeout, >=))
- ifi->state = S_INIT;
- else {
- destination.sin_addr.s_addr = INADDR_BROADCAST;
- from.s_addr = INADDR_ANY;
- }
- break;
- default:
- ifi->state = S_INIT;
- break;
- }
-
- if (ifi->state == S_INIT) {
- /* Something has gone wrong. Start over. */
- state_init(ifi);
- return;
- }
-
- set_resend_timeout(ifi, &now, send_request);
- set_interval(ifi, &now);
- set_secs(ifi, &now);
-
- rslt = send_packet(ifi, from, destination.sin_addr, "DHCPREQUEST");
- if (rslt != -1 && log_getverbose()) {
- addr = strdup(inet_ntoa(ifi->requested_address));
- if (addr == NULL)
- fatal("strdup(ifi->requested_address)");
- if (destination.sin_addr.s_addr == INADDR_BROADCAST)
- log_debug("%s: DHCPREQUEST %s", log_procname, addr);
- else
- log_debug("%s: DHCPREQUEST %s from %s", log_procname,
- addr, inet_ntoa(destination.sin_addr));
- free(addr);
- }
-
- tick_msg("lease", TICK_WAIT);
-}
-
-void
-send_decline(struct interface_info *ifi)
-{
- ssize_t rslt;
-
- rslt = send_packet(ifi, inaddr_any, inaddr_broadcast, "DHCPDECLINE");
- if (rslt != -1)
- log_debug("%s: DHCPDECLINE", log_procname);
-}
-
-void
-send_release(struct interface_info *ifi)
-{
- ssize_t rslt;
-
- rslt = send_packet(ifi, ifi->configured->address, ifi->destination,
- "DHCPRELEASE");
- if (rslt != -1)
- log_debug("%s: DHCPRELEASE", log_procname);
-}
-
-void
-make_discover(struct interface_info *ifi, struct client_lease *lease)
-{
- struct option_data options[DHO_COUNT];
- struct dhcp_packet *packet = &ifi->sent_packet;
- unsigned char discover = DHCPDISCOVER;
- int i;
-
- memset(options, 0, sizeof(options));
- memset(packet, 0, sizeof(*packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPDISCOVER */
- i = DHO_DHCP_MESSAGE_TYPE;
- options[i].data = &discover;
- options[i].len = sizeof(discover);
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options[i].data = config->requested_options;
- options[i].len = config->requested_option_count;
-
- /* If we had an address, try to get it again. */
- if (lease != NULL) {
- ifi->requested_address = lease->address;
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options[i].data = (char *)&lease->address;
- options[i].len = sizeof(lease->address);
- } else
- ifi->requested_address.s_addr = INADDR_ANY;
-
- /* Send any options requested in the config file. */
- for (i = 0; i < DHO_COUNT; i++)
- if (options[i].data == NULL &&
- config->send_options[i].data != NULL) {
- options[i].data = config->send_options[i].data;
- options[i].len = config->send_options[i].len;
- }
-
- /*
- * Set up the option buffer to fit in a 576-byte UDP packet, which
- * RFC 791 says is the largest packet that *MUST* be accepted
- * by any host.
- */
- i = pack_options(ifi->sent_packet.options, 576 - DHCP_FIXED_LEN,
- options);
- if (i == -1 || packet->options[i] != DHO_END)
- fatalx("options do not fit in DHCPDISCOVER packet");
- ifi->sent_packet_length = DHCP_FIXED_NON_UDP+i+1;
- if (ifi->sent_packet_length < BOOTP_MIN_LEN)
- ifi->sent_packet_length = BOOTP_MIN_LEN;
-
- packet->op = BOOTREQUEST;
- packet->htype = HTYPE_ETHER;
- packet->hlen = ETHER_ADDR_LEN;
- packet->hops = 0;
- packet->xid = ifi->xid;
- packet->secs = 0; /* filled in by send_discover. */
- packet->flags = 0;
-
- packet->ciaddr.s_addr = INADDR_ANY;
- packet->yiaddr.s_addr = INADDR_ANY;
- packet->siaddr.s_addr = INADDR_ANY;
- packet->giaddr.s_addr = INADDR_ANY;
-
- memcpy(&packet->chaddr, ifi->hw_address.ether_addr_octet,
- ETHER_ADDR_LEN);
-}
-
-void
-make_request(struct interface_info *ifi, struct client_lease *lease)
-{
- struct option_data options[DHO_COUNT];
- struct dhcp_packet *packet = &ifi->sent_packet;
- unsigned char request = DHCPREQUEST;
- int i;
-
- memset(options, 0, sizeof(options));
- memset(packet, 0, sizeof(*packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPREQUEST */
- i = DHO_DHCP_MESSAGE_TYPE;
- options[i].data = &request;
- options[i].len = sizeof(request);
-
- /* Request the options we want */
- i = DHO_DHCP_PARAMETER_REQUEST_LIST;
- options[i].data = config->requested_options;
- options[i].len = config->requested_option_count;
-
- /*
- * If we are requesting an address that hasn't yet been assigned
- * to us, use the DHCP Requested Address option.
- */
- if (ifi->state == S_REQUESTING) {
- /* Send back the server identifier. */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options[i].data = lease->options[i].data;
- options[i].len = lease->options[i].len;
- }
- if (ifi->state == S_REQUESTING ||
- ifi->state == S_REBOOTING) {
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options[i].data = (char *)&lease->address.s_addr;
- options[i].len = sizeof(lease->address.s_addr);
- }
-
- /* Send any options requested in the config file. */
- for (i = 0; i < DHO_COUNT; i++)
- if (options[i].data == NULL &&
- config->send_options[i].data != NULL) {
- options[i].data = config->send_options[i].data;
- options[i].len = config->send_options[i].len;
- }
-
- /*
- * Set up the option buffer to fit in a 576-byte UDP packet, which
- * RFC 791 says is the largest packet that *MUST* be accepted
- * by any host.
- */
- i = pack_options(ifi->sent_packet.options, 576 - DHCP_FIXED_LEN,
- options);
- if (i == -1 || packet->options[i] != DHO_END)
- fatalx("options do not fit in DHCPREQUEST packet");
- ifi->sent_packet_length = DHCP_FIXED_NON_UDP+i+1;
- if (ifi->sent_packet_length < BOOTP_MIN_LEN)
- ifi->sent_packet_length = BOOTP_MIN_LEN;
-
- packet->op = BOOTREQUEST;
- packet->htype = HTYPE_ETHER;
- packet->hlen = ETHER_ADDR_LEN;
- packet->hops = 0;
- packet->xid = ifi->xid;
- packet->secs = 0; /* Filled in by send_request. */
- packet->flags = 0;
-
- /*
- * If we own the address we're requesting, put it in ciaddr. Otherwise
- * set ciaddr to zero.
- */
- ifi->requested_address = lease->address;
- if (ifi->state == S_BOUND ||
- ifi->state == S_RENEWING)
- packet->ciaddr.s_addr = lease->address.s_addr;
- else
- packet->ciaddr.s_addr = INADDR_ANY;
-
- packet->yiaddr.s_addr = INADDR_ANY;
- packet->siaddr.s_addr = INADDR_ANY;
- packet->giaddr.s_addr = INADDR_ANY;
-
- memcpy(&packet->chaddr, ifi->hw_address.ether_addr_octet,
- ETHER_ADDR_LEN);
-}
-
-void
-make_decline(struct interface_info *ifi, struct client_lease *lease)
-{
- struct option_data options[DHO_COUNT];
- struct dhcp_packet *packet = &ifi->sent_packet;
- unsigned char decline = DHCPDECLINE;
- int i;
-
- memset(options, 0, sizeof(options));
- memset(packet, 0, sizeof(*packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPDECLINE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options[i].data = &decline;
- options[i].len = sizeof(decline);
-
- /* Send back the server identifier. */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options[i].data = lease->options[i].data;
- options[i].len = lease->options[i].len;
-
- /* Send back the address we're declining. */
- i = DHO_DHCP_REQUESTED_ADDRESS;
- options[i].data = (char *)&lease->address.s_addr;
- options[i].len = sizeof(lease->address.s_addr);
-
- /* Send the uid if the user supplied one. */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- if (config->send_options[i].len != 0) {
- options[i].data = config->send_options[i].data;
- options[i].len = config->send_options[i].len;
- }
-
- /*
- * Set up the option buffer to fit in a 576-byte UDP packet, which
- * RFC 791 says is the largest packet that *MUST* be accepted
- * by any host.
- */
- i = pack_options(ifi->sent_packet.options, 576 - DHCP_FIXED_LEN,
- options);
- if (i == -1 || packet->options[i] != DHO_END)
- fatalx("options do not fit in DHCPDECLINE packet");
- ifi->sent_packet_length = DHCP_FIXED_NON_UDP+i+1;
- if (ifi->sent_packet_length < BOOTP_MIN_LEN)
- ifi->sent_packet_length = BOOTP_MIN_LEN;
-
- packet->op = BOOTREQUEST;
- packet->htype = HTYPE_ETHER;
- packet->hlen = ETHER_ADDR_LEN;
- packet->hops = 0;
- packet->xid = ifi->xid;
- packet->secs = 0;
- packet->flags = 0;
-
- /* ciaddr must always be zero. */
- packet->ciaddr.s_addr = INADDR_ANY;
- packet->yiaddr.s_addr = INADDR_ANY;
- packet->siaddr.s_addr = INADDR_ANY;
- packet->giaddr.s_addr = INADDR_ANY;
-
- memcpy(&packet->chaddr, ifi->hw_address.ether_addr_octet,
- ETHER_ADDR_LEN);
-}
-
-void
-make_release(struct interface_info *ifi, struct client_lease *lease)
-{
- struct option_data options[DHO_COUNT];
- struct dhcp_packet *packet = &ifi->sent_packet;
- unsigned char release = DHCPRELEASE;
- int i;
-
- memset(options, 0, sizeof(options));
- memset(packet, 0, sizeof(*packet));
-
- /* Set DHCP_MESSAGE_TYPE to DHCPRELEASE */
- i = DHO_DHCP_MESSAGE_TYPE;
- options[i].data = &release;
- options[i].len = sizeof(release);
-
- /* Send back the server identifier. */
- i = DHO_DHCP_SERVER_IDENTIFIER;
- options[i].data = lease->options[i].data;
- options[i].len = lease->options[i].len;
-
- i = pack_options(ifi->sent_packet.options, 576 - DHCP_FIXED_LEN,
- options);
- if (i == -1 || packet->options[i] != DHO_END)
- fatalx("options do not fit in DHCPRELEASE packet");
- ifi->sent_packet_length = DHCP_FIXED_NON_UDP+i+1;
- if (ifi->sent_packet_length < BOOTP_MIN_LEN)
- ifi->sent_packet_length = BOOTP_MIN_LEN;
-
- packet->op = BOOTREQUEST;
- packet->htype = HTYPE_ETHER;
- packet->hlen = ETHER_ADDR_LEN;
- packet->hops = 0;
- packet->xid = ifi->xid;
- packet->secs = 0;
- packet->flags = 0;
-
- /*
- * Note we return the *offered* address. NOT the configured address
- * which could have been changed via dhclient.conf. But the packet
- * is sent from the *configured* address.
- *
- * This might easily confuse a server, but if you play with fire
- * by modifying the address you are on your own!
- */
- packet->ciaddr.s_addr = ifi->active->address.s_addr;
- packet->yiaddr.s_addr = INADDR_ANY;
- packet->siaddr.s_addr = INADDR_ANY;
- packet->giaddr.s_addr = INADDR_ANY;
-
- memcpy(&packet->chaddr, ifi->hw_address.ether_addr_octet,
- ETHER_ADDR_LEN);
-}
-
-void
-free_client_lease(struct client_lease *lease)
-{
- int i;
-
- if (lease == NULL)
- return;
-
- free(lease->server_name);
- free(lease->filename);
- for (i = 0; i < DHO_COUNT; i++)
- free(lease->options[i].data);
-
- free(lease);
-}
-
-void
-write_lease_db(struct interface_info *ifi)
-{
- struct client_lease_tq *lease_db = &ifi->lease_db;
- struct client_lease *lp, *pl;
- char *leasestr;
-
- TAILQ_FOREACH_SAFE(lp, lease_db, next, pl) {
- if (lp != ifi->active && lease_expiry(lp) == 0) {
- TAILQ_REMOVE(lease_db, lp, next);
- free_client_lease(lp);
- }
- }
-
- if (leaseFile == NULL)
- return;
-
- rewind(leaseFile);
-
- /*
- * The leases file is kept in chronological order, with the
- * most recently bound lease last. When the file was read
- * leases that were not expired were added to the head of the
- * TAILQ ifi->leases as they were read. Therefore write out
- * the leases in ifi->leases in reverse order to recreate
- * the chonological order required.
- */
- TAILQ_FOREACH_REVERSE(lp, lease_db, client_lease_tq, next) {
- leasestr = lease_as_string("lease", lp);
- if (leasestr != NULL)
- fprintf(leaseFile, "%s", leasestr);
- else
- log_warnx("%s: cannot make lease into string",
- log_procname);
- }
-
- fflush(leaseFile);
- ftruncate(fileno(leaseFile), ftello(leaseFile));
- fsync(fileno(leaseFile));
-}
-
-void
-append_statement(char *string, size_t sz, char *s1, char *s2)
-{
- strlcat(string, s1, sz);
- strlcat(string, s2, sz);
- strlcat(string, ";\n", sz);
-}
-
-struct unwind_info *
-lease_as_unwind_info(struct client_lease *lease)
-{
- struct unwind_info *unwind_info;
- struct option_data *opt;
- unsigned int servers;
-
- unwind_info = calloc(1, sizeof(*unwind_info));
- if (unwind_info == NULL)
- fatal("unwind_info");
-
- opt = &lease->options[DHO_DOMAIN_NAME_SERVERS];
- if (opt->len != 0) {
- servers = opt->len / sizeof(in_addr_t);
- if (servers > MAXNS)
- servers = MAXNS;
- if (servers > 0) {
- unwind_info->count = servers;
- memcpy(unwind_info->ns, opt->data, servers *
- sizeof(in_addr_t));
- }
- }
-
- if (unwind_info->count == 0) {
- free(unwind_info);
- unwind_info = NULL;
- }
-
- return unwind_info;
-}
-
-struct proposal *
-lease_as_proposal(struct client_lease *lease)
-{
- uint8_t defroute[5]; /* 1 + sizeof(in_addr_t) */
- struct option_data fake;
- struct option_data *opt;
- struct proposal *proposal;
- uint8_t *ns, *p, *routes, *domains;
- unsigned int routes_len = 0, domains_len = 0, ns_len = 0;
- uint16_t mtu;
-
- /* Determine sizes of variable length data. */
- opt = NULL;
- if (lease->options[DHO_CLASSLESS_STATIC_ROUTES].len != 0) {
- opt = &lease->options[DHO_CLASSLESS_STATIC_ROUTES];
- } else if (lease->options[DHO_CLASSLESS_MS_STATIC_ROUTES].len != 0) {
- opt = &lease->options[DHO_CLASSLESS_MS_STATIC_ROUTES];
- } else if (lease->options[DHO_ROUTERS].len != 0) {
- /* Fake a classless static default route. */
- opt = &lease->options[DHO_ROUTERS];
- fake.len = sizeof(defroute);
- fake.data = defroute;
- fake.data[0] = 0;
- memcpy(&fake.data[1], opt->data, sizeof(defroute) - 1);
- opt = &fake;
- }
- if (opt != NULL) {
- routes_len = opt->len;
- routes = opt->data;
- }
-
- opt = NULL;
- if (lease->options[DHO_DOMAIN_SEARCH].len != 0)
- opt = &lease->options[DHO_DOMAIN_SEARCH];
- else if (lease->options[DHO_DOMAIN_NAME].len != 0)
- opt = &lease->options[DHO_DOMAIN_NAME];
- if (opt != NULL) {
- domains_len = opt->len;
- domains = opt->data;
- }
-
- if (lease->options[DHO_DOMAIN_NAME_SERVERS].len != 0) {
- opt = &lease->options[DHO_DOMAIN_NAME_SERVERS];
- ns_len = opt->len;
- ns = opt->data;
- }
-
- /* Allocate proposal. */
- proposal = calloc(1, sizeof(*proposal) + routes_len + domains_len +
- ns_len);
- if (proposal == NULL)
- fatal("proposal");
-
- /* Fill in proposal. */
- proposal->address = lease->address;
-
- opt = &lease->options[DHO_INTERFACE_MTU];
- if (opt->len == sizeof(mtu)) {
- memcpy(&mtu, opt->data, sizeof(mtu));
- proposal->mtu = ntohs(mtu);
- }
-
- opt = &lease->options[DHO_SUBNET_MASK];
- if (opt->len == sizeof(proposal->netmask))
- memcpy(&proposal->netmask, opt->data, opt->len);
-
- /* Append variable length uint8_t data. */
- p = (uint8_t *)proposal + sizeof(struct proposal);
- memcpy(p, routes, routes_len);
- p += routes_len;
- proposal->routes_len = routes_len;
- memcpy(p, domains, domains_len);
- p += domains_len;
- proposal->domains_len = domains_len;
- memcpy(p, ns, ns_len);
- proposal->ns_len = ns_len;
-
- return proposal;
-}
-
-char *
-lease_as_string(char *type, struct client_lease *lease)
-{
- static char string[8192];
- char timebuf[27]; /* 6 2017/04/08 05:47:50 UTC; */
- struct option_data *opt;
- struct tm *tm;
- char *buf, *name;
- time_t t;
- size_t rslt;
- int i;
-
- memset(string, 0, sizeof(string));
-
- strlcat(string, type, sizeof(string));
- strlcat(string, " {\n", sizeof(string));
- strlcat(string, BOOTP_LEASE(lease) ? " bootp;\n" : "", sizeof(string));
-
- append_statement(string, sizeof(string), " fixed-address ",
- inet_ntoa(lease->address));
- append_statement(string, sizeof(string), " next-server ",
- inet_ntoa(lease->next_server));
-
- if (lease->filename != NULL) {
- buf = pretty_print_string(lease->filename,
- strlen(lease->filename), 1);
- if (buf == NULL)
- return NULL;
- append_statement(string, sizeof(string), " filename ", buf);
- }
- if (lease->server_name != NULL) {
- buf = pretty_print_string(lease->server_name,
- strlen(lease->server_name), 1);
- if (buf == NULL)
- return NULL;
- append_statement(string, sizeof(string), " server-name ",
- buf);
- }
- if (lease->ssid_len != 0) {
- buf = pretty_print_string(lease->ssid, lease->ssid_len, 1);
- if (buf == NULL)
- return NULL;
- append_statement(string, sizeof(string), " ssid ", buf);
- }
-
- for (i = 0; i < DHO_COUNT; i++) {
- opt = &lease->options[i];
- if (opt->len == 0)
- continue;
- name = code_to_name(i);
-
- buf = pretty_print_option(i, opt, 1);
- if (strlen(buf) == 0)
- continue;
- strlcat(string, " option ", sizeof(string));
- strlcat(string, name, sizeof(string));
- append_statement(string, sizeof(string), " ", buf);
- }
-
- i = asprintf(&buf, "%lld", (long long)lease->epoch);
- if (i == -1)
- return NULL;
- append_statement(string, sizeof(string), " epoch ", buf);
- free(buf);
-
- t = lease->epoch + lease_renewal(lease);
- if ((tm = gmtime(&t)) == NULL)
- return NULL;
- rslt = strftime(timebuf, sizeof(timebuf), DB_TIMEFMT, tm);
- if (rslt == 0)
- return NULL;
- append_statement(string, sizeof(string), " renew ", timebuf);
-
- t = lease->epoch + lease_rebind(lease);
- if ((tm = gmtime(&t)) == NULL)
- return NULL;
- rslt = strftime(timebuf, sizeof(timebuf), DB_TIMEFMT, tm);
- if (rslt == 0)
- return NULL;
- append_statement(string, sizeof(string), " rebind ", timebuf);
-
- t = lease->epoch + lease_expiry(lease);
- if ((tm = gmtime(&t)) == NULL)
- return NULL;
- rslt = strftime(timebuf, sizeof(timebuf), DB_TIMEFMT, tm);
- if (rslt == 0)
- return NULL;
- append_statement(string, sizeof(string), " expire ", timebuf);
-
- rslt = strlcat(string, "}\n", sizeof(string));
- if (rslt >= sizeof(string))
- return NULL;
-
- return string;
-}
-
-void
-go_daemon(void)
-{
- static int daemonized = 0;
-
- if ((cmd_opts & OPT_FOREGROUND) != 0 || daemonized != 0)
- return;
-
- daemonized = 1;
-
- if (rdaemon(nullfd) == -1)
- fatal("daemonize");
-
- /* Stop logging to stderr. */
- log_init(0, LOG_DAEMON);
- if ((cmd_opts & OPT_VERBOSE) != 0)
- log_setverbose(1); /* Show log_debug() messages. */
- log_procinit(log_procname);
-
- setproctitle("%s", log_procname);
- signal(SIGHUP, SIG_IGN);
- signal(SIGPIPE, SIG_IGN);
-}
-
-int
-rdaemon(int devnull)
-{
- if (devnull == -1) {
- errno = EBADF;
- return -1;
- }
- if (fcntl(devnull, F_GETFL) == -1)
- return -1;
-
- switch (fork()) {
- case -1:
- return -1;
- case 0:
- break;
- default:
- _exit(0);
- }
-
- if (setsid() == -1)
- return -1;
-
- (void)dup2(devnull, STDIN_FILENO);
- (void)dup2(devnull, STDOUT_FILENO);
- (void)dup2(devnull, STDERR_FILENO);
- if (devnull > 2)
- (void)close(devnull);
-
- return 0;
-}
-
-/*
- * resolv_conf(5) says a max of DHCP_DOMAIN_SEARCH_CNT domains and total
- * length of DHCP_DOMAIN_SEARCH_LEN bytes are acceptable for the 'search'
- * statement.
- */
-int
-res_hnok_list(const char *names)
-{
- char *dupnames, *hn, *inputstring;
- int count;
-
- if (strlen(names) >= DHCP_DOMAIN_SEARCH_LEN)
- return 0;
-
- dupnames = inputstring = strdup(names);
- if (inputstring == NULL)
- fatal("domain name list");
-
- count = 0;
- while ((hn = strsep(&inputstring, " \t")) != NULL) {
- if (strlen(hn) == 0)
- continue;
- if (res_hnok(hn) == 0)
- break;
- count++;
- if (count > DHCP_DOMAIN_SEARCH_CNT)
- break;
- }
-
- free(dupnames);
-
- return count > 0 && count < 7 && hn == NULL;
-}
-
-/*
- * Decode a byte string encoding a list of domain names as specified in RFC1035
- * section 4.1.4.
- *
- * The result is a string consisting of a blank separated list of domain names.
- *
- * e.g.
- *
- * 3:65:6e:67:5:61:70:70:6c:65:3:63:6f:6d:0:9:6d:61:72:6b:65:74:69:6e:67:c0:04
- *
- * which represents
- *
- * 3 |'e'|'n'|'g'| 5 |'a'|'p'|'p'|'l'|
- * 'e'| 3 |'c'|'o'|'m'| 0 | 9 |'m'|'a'|
- * 'r'|'k'|'e'|'t'|'i'|'n'|'g'|xC0|x04|
- *
- * will be translated to
- *
- * "eng.apple.com. marketing.apple.com."
- */
-char *
-rfc1035_as_string(unsigned char *src, size_t srclen)
-{
- static char search[DHCP_DOMAIN_SEARCH_LEN];
- unsigned char name[DHCP_DOMAIN_SEARCH_LEN];
- unsigned char *endsrc, *cp;
- int len, domains;
-
- memset(search, 0, sizeof(search));
-
- /* Compute expanded length. */
- domains = 0;
- cp = src;
- endsrc = src + srclen;
-
- while (cp < endsrc && domains < DHCP_DOMAIN_SEARCH_CNT) {
- len = dn_expand(src, endsrc, cp, name, sizeof(name));
- if (len == -1)
- goto bad;
- cp += len;
- if (domains > 0)
- strlcat(search, " ", sizeof(search));
- strlcat(search, name, sizeof(search));
- if (strlcat(search, ".", sizeof(search)) >= sizeof(search))
- goto bad;
- domains++;
- }
-
- return search;
-
-bad:
- memset(search, 0, sizeof(search));
- return search;
-}
-
-void
-fork_privchld(struct interface_info *ifi, int fd, int fd2)
-{
- struct pollfd pfd[1];
- struct imsgbuf *priv_ibuf;
- ssize_t n;
- int ioctlfd, routefd, nfds, rslt;
-
- switch (fork()) {
- case -1:
- fatal("fork");
- break;
- case 0:
- break;
- default:
- return;
- }
-
- if (chdir("/") == -1)
- fatal("chdir(\"/\")");
-
- go_daemon();
-
- free(log_procname);
- rslt = asprintf(&log_procname, "%s [priv]", ifi->name);
- if (rslt == -1)
- fatal("log_procname");
- setproctitle("%s", log_procname);
- log_procinit(log_procname);
-
- close(fd2);
-
- if ((priv_ibuf = malloc(sizeof(*priv_ibuf))) == NULL)
- fatal("priv_ibuf");
-
- imsg_init(priv_ibuf, fd);
-
- if ((ioctlfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- fatal("socket(AF_INET, SOCK_DGRAM)");
- if ((routefd = socket(AF_ROUTE, SOCK_RAW, 0)) == -1)
- fatal("socket(AF_ROUTE, SOCK_RAW)");
-
- if (unveil(_PATH_RESCONF, "wc") == -1)
- fatal("unveil %s", _PATH_RESCONF);
- if (unveil("/etc/resolv.conf.tail", "r") == -1)
- fatal("unveil /etc/resolve.conf.tail");
- if (unveil(NULL, NULL) == -1)
- fatal("unveil");
-
- while (quit == 0) {
- pfd[0].fd = priv_ibuf->fd;
- pfd[0].events = POLLIN;
-
- nfds = ppoll(pfd, 1, NULL, NULL);
- if (nfds == -1) {
- if (errno == EINTR)
- continue;
- log_warn("%s: ppoll(priv_ibuf)", log_procname);
- break;
- }
- if ((pfd[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0)
- break;
- if (nfds == 0 || (pfd[0].revents & POLLIN) == 0)
- continue;
-
- if ((n = imsg_read(priv_ibuf)) == -1 && errno != EAGAIN) {
- log_warn("%s: imsg_read(priv_ibuf)", log_procname);
- break;
- }
- if (n == 0) {
- /* Connection closed - other end should log message. */
- break;
- }
-
- dispatch_imsg(ifi->name, ifi->rdomain, ioctlfd, routefd,
- priv_ibuf);
- }
- close(routefd);
- close(ioctlfd);
-
- imsg_clear(priv_ibuf);
- close(fd);
-
- exit(1);
-}
-
-struct client_lease *
-apply_defaults(struct client_lease *lease)
-{
- struct option_data emptyopt = {0, NULL};
- struct client_lease *newlease;
- char *fmt;
- int i;
-
- newlease = clone_lease(lease);
- if (newlease == NULL)
- fatalx("unable to clone lease");
-
- if (config->filename != NULL) {
- free(newlease->filename);
- newlease->filename = strdup(config->filename);
- if (newlease->filename == NULL)
- fatal("strdup(config->filename)");
- }
- if (config->server_name != NULL) {
- free(newlease->server_name);
- newlease->server_name = strdup(config->server_name);
- if (newlease->server_name == NULL)
- fatal("strdup(config->server_name)");
- }
- if (config->address.s_addr != INADDR_ANY)
- newlease->address.s_addr = config->address.s_addr;
- if (config->next_server.s_addr != INADDR_ANY)
- newlease->next_server.s_addr = config->next_server.s_addr;
-
- for (i = 0; i < DHO_COUNT; i++) {
- fmt = code_to_format(i);
- switch (config->default_actions[i]) {
- case ACTION_IGNORE:
- merge_option_data(fmt, &emptyopt, &emptyopt,
- &newlease->options[i]);
- break;
-
- case ACTION_SUPERSEDE:
- merge_option_data(fmt, &config->defaults[i], &emptyopt,
- &newlease->options[i]);
- break;
-
- case ACTION_PREPEND:
- merge_option_data(fmt, &config->defaults[i],
- &lease->options[i], &newlease->options[i]);
- break;
-
- case ACTION_APPEND:
- merge_option_data(fmt, &lease->options[i],
- &config->defaults[i], &newlease->options[i]);
- break;
-
- case ACTION_DEFAULT:
- if (newlease->options[i].len == 0)
- merge_option_data(fmt, &config->defaults[i],
- &emptyopt, &newlease->options[i]);
- break;
-
- default:
- break;
- }
- }
-
- if (newlease->options[DHO_STATIC_ROUTES].len != 0) {
- log_debug("%s: DHO_STATIC_ROUTES (option 33) not supported",
- log_procname);
- free(newlease->options[DHO_STATIC_ROUTES].data);
- newlease->options[DHO_STATIC_ROUTES].data = NULL;
- newlease->options[DHO_STATIC_ROUTES].len = 0;
- }
-
- /*
- * RFC 3442 says client *MUST* ignore DHO_ROUTERS
- * when DHO_CLASSLESS_[MS_]_ROUTES present.
- */
- if ((newlease->options[DHO_CLASSLESS_MS_STATIC_ROUTES].len != 0) ||
- (newlease->options[DHO_CLASSLESS_STATIC_ROUTES].len != 0)) {
- free(newlease->options[DHO_ROUTERS].data);
- newlease->options[DHO_ROUTERS].data = NULL;
- newlease->options[DHO_ROUTERS].len = 0;
- }
-
- return newlease;
-}
-
-struct client_lease *
-clone_lease(struct client_lease *oldlease)
-{
- struct client_lease *newlease;
- int i;
-
- newlease = calloc(1, sizeof(*newlease));
- if (newlease == NULL)
- goto cleanup;
-
- newlease->epoch = oldlease->epoch;
- newlease->address = oldlease->address;
- newlease->next_server = oldlease->next_server;
- memcpy(newlease->ssid, oldlease->ssid, sizeof(newlease->ssid));
- newlease->ssid_len = oldlease->ssid_len;
-
- if (oldlease->server_name != NULL) {
- newlease->server_name = strdup(oldlease->server_name);
- if (newlease->server_name == NULL)
- goto cleanup;
- }
- if (oldlease->filename != NULL) {
- newlease->filename = strdup(oldlease->filename);
- if (newlease->filename == NULL)
- goto cleanup;
- }
-
- for (i = 0; i < DHO_COUNT; i++) {
- if (oldlease->options[i].len == 0)
- continue;
- newlease->options[i].len = oldlease->options[i].len;
- newlease->options[i].data = calloc(1,
- newlease->options[i].len);
- if (newlease->options[i].data == NULL)
- goto cleanup;
- memcpy(newlease->options[i].data, oldlease->options[i].data,
- newlease->options[i].len);
- }
-
- return newlease;
-
-cleanup:
- free_client_lease(newlease);
-
- return NULL;
-}
-
-int
-autoconf(struct interface_info *ifi)
-{
- struct ifreq ifr;
- int ioctlfd;
-
- if ((ioctlfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
- fatal("socket(AF_INET, SOCK_DGRAM)");
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, ifi->name, sizeof(ifr.ifr_name));
-
- if (ioctl(ioctlfd, SIOCGIFXFLAGS, (caddr_t)&ifr) < 0)
- fatal("SIOGIFXFLAGS");
-
- close(ioctlfd);
-
- return ifr.ifr_flags & IFXF_AUTOCONF4;
-}
-
-int
-take_charge(struct interface_info *ifi, int routefd, char *leasespath)
-{
- const struct timespec max_timeout = { 9, 0 };
- const struct timespec resend_intvl = { 3, 0 };
- const struct timespec leasefile_intvl = { 0, 3000000 };
- struct timespec now, resend, stop, timeout;
- struct pollfd fds[1];
- struct rt_msghdr rtm;
- int fd, nfds;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- resend = now;
- timespecadd(&now, &max_timeout, &stop);
-
- /*
- * Send RTM_PROPOSAL with RTF_PROTO3 set.
- *
- * When it comes back, we're in charge and other dhclients are
- * dead processes walking.
- */
- memset(&rtm, 0, sizeof(rtm));
-
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_type = RTM_PROPOSAL;
- rtm.rtm_msglen = sizeof(rtm);
- rtm.rtm_tableid = ifi->rdomain;
- rtm.rtm_index = ifi->index;
- rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
- rtm.rtm_addrs = 0;
- rtm.rtm_flags = RTF_UP | RTF_PROTO3;
-
- for (fd = -1; fd == -1 && quit != TERMINATE;) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (timespeccmp(&now, &stop, >=))
- fatalx("failed to take charge");
-
- if ((ifi->flags & IFI_IN_CHARGE) == 0) {
- if (timespeccmp(&now, &resend, >=)) {
- timespecadd(&resend, &resend_intvl, &resend);
- rtm.rtm_seq = ifi->xid = arc4random();
- if (write(routefd, &rtm, sizeof(rtm)) == -1)
- fatal("write(routefd)");
- }
- timespecsub(&resend, &now, &timeout);
- } else {
- /*
- * Keep trying to open leasefile in 3ms intervals
- * while continuing to process any RTM_* messages
- * that come in.
- */
- timeout = leasefile_intvl;
- }
-
- fds[0].fd = routefd;
- fds[0].events = POLLIN;
- nfds = ppoll(fds, 1, &timeout, NULL);
- if (nfds == -1) {
- if (errno == EINTR)
- continue;
- fatal("ppoll(routefd)");
- }
-
- if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0)
- fatalx("routefd: ERR|HUP|NVAL");
- if (nfds == 1 && (fds[0].revents & POLLIN) == POLLIN)
- routefd_handler(ifi, routefd);
-
- if (quit != TERMINATE && (ifi->flags & IFI_IN_CHARGE) == IFI_IN_CHARGE) {
- fd = open(leasespath, O_NONBLOCK |
- O_RDONLY|O_EXLOCK|O_CREAT|O_NOFOLLOW, 0640);
- if (fd == -1 && errno != EWOULDBLOCK)
- break;
- }
- }
-
- return fd;
-}
-
-struct client_lease *
-get_recorded_lease(struct interface_info *ifi)
-{
- char ifname[IF_NAMESIZE];
- struct client_lease *lp;
- int i;
-
- /* Update on-disk db, which clears out expired leases. */
- ifi->active = NULL;
- write_lease_db(ifi);
-
- /* Run through the list of leases and see if one can be used. */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- TAILQ_FOREACH(lp, &ifi->lease_db, next) {
- if (lp->ssid_len != ifi->ssid_len)
- continue;
- if (memcmp(lp->ssid, ifi->ssid, lp->ssid_len) != 0)
- continue;
- if ((lp->options[i].len != 0) && ((lp->options[i].len !=
- config->send_options[i].len) ||
- memcmp(lp->options[i].data, config->send_options[i].data,
- lp->options[i].len) != 0))
- continue;
- if (addressinuse(ifi->name, lp->address, ifname) != 0 &&
- strncmp(ifname, ifi->name, IF_NAMESIZE) != 0)
- continue;
- break;
- }
-
- return lp;
-}
-
-time_t
-lease_expiry(struct client_lease *lease)
-{
- time_t cur_time;
- uint32_t expiry;
-
- time(&cur_time);
- expiry = 0;
- if (lease->options[DHO_DHCP_LEASE_TIME].len == sizeof(expiry)) {
- memcpy(&expiry, lease->options[DHO_DHCP_LEASE_TIME].data,
- sizeof(expiry));
- expiry = ntohl(expiry);
- if (expiry < 60)
- expiry = 60;
- }
- expiry = lease->epoch + expiry - cur_time;
-
- return (expiry > 0) ? expiry : 0;
-}
-
-time_t
-lease_renewal(struct client_lease *lease)
-{
- time_t cur_time, expiry;
- uint32_t renewal;
-
- time(&cur_time);
- expiry = lease_expiry(lease);
-
- renewal = expiry / 2;
- if (lease->options[DHO_DHCP_RENEWAL_TIME].len == sizeof(renewal)) {
- memcpy(&renewal, lease->options[DHO_DHCP_RENEWAL_TIME].data,
- sizeof(renewal));
- renewal = ntohl(renewal);
- }
- renewal = lease->epoch + renewal - cur_time;
-
- return (renewal > 0) ? renewal : 0;
-}
-
-time_t
-lease_rebind(struct client_lease *lease)
-{
- time_t cur_time, expiry;
- uint32_t rebind;
-
- time(&cur_time);
- expiry = lease_expiry(lease);
-
- rebind = (expiry / 8) * 7;
- if (lease->options[DHO_DHCP_REBINDING_TIME].len == sizeof(rebind)) {
- memcpy(&rebind, lease->options[DHO_DHCP_REBINDING_TIME].data,
- sizeof(rebind));
- rebind = ntohl(rebind);
- }
- rebind = lease->epoch + rebind - cur_time;
-
- return (rebind > 0) ? rebind : 0;
-}
-
-void
-get_lease_timeouts(struct interface_info *ifi, struct client_lease *lease)
-{
- struct timespec now, interval;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- timespecclear(&interval);
-
- interval.tv_sec = lease_expiry(lease);
- timespecadd(&now, &interval, &ifi->expiry);
-
- interval.tv_sec = lease_rebind(lease);
- timespecadd(&now, &interval, &ifi->rebind);
-
- interval.tv_sec = lease_renewal(lease);
- timespecadd(&now, &interval, &ifi->renew);
-
- if (timespeccmp(&ifi->rebind, &ifi->expiry, >))
- ifi->rebind = ifi->expiry;
- if (timespeccmp(&ifi->renew, &ifi->rebind, >))
- ifi->renew = ifi->rebind;
-}
-
-void
-tick_msg(const char *preamble, int action)
-{
- const struct timespec grace_intvl = {3, 0};
- const struct timespec link_intvl = {config->link_interval, 0};
- static struct timespec grace, stop;
- struct timespec now;
- static int linkup, preamble_sent, sleeping;
- int printmsg;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
-
- if (!timespecisset(&stop)) {
- preamble_sent = 0;
- timespecadd(&now, &link_intvl, &stop);
- timespecadd(&now, &grace_intvl, &grace);
- return;
- }
-
- if (isatty(STDERR_FILENO) == 0 || sleeping == 1)
- printmsg = 0; /* Already in the background. */
- else if (timespeccmp(&now, &grace, <))
- printmsg = 0; /* Wait a bit before speaking. */
- else if (linkup && strcmp("link", preamble) == 0)
- printmsg = 0; /* One 'got link' is enough for anyone. */
- else if (log_getverbose())
- printmsg = 0; /* Verbose has sufficent verbiage. */
- else
- printmsg = 1;
-
- if (timespeccmp(&now, &stop, >=)) {
- if (action == TICK_WAIT)
- action = TICK_DAEMON;
- if (linkup == 0) {
- log_debug("%s: link timeout (%lld seconds) expired",
- log_procname, (long long)link_intvl.tv_sec);
- linkup = 1;
- }
- }
-
- if (printmsg && preamble_sent == 0) {
- fprintf(stderr, "%s: no %s...", log_procname, preamble);
- preamble_sent = 1;
- }
-
- switch (action) {
- case TICK_SUCCESS:
- if (printmsg)
- fprintf(stderr, "got %s\n", preamble);
- preamble_sent = 0;
- if (strcmp("link", preamble) == 0) {
- linkup = 1;
- /* New silent period for "no lease ... got lease". */
- timespecadd(&now, &grace_intvl, &grace);
- }
- break;
- case TICK_WAIT:
- if (printmsg)
- fprintf(stderr, ".");
- break;
- case TICK_DAEMON:
- if (printmsg)
- fprintf(stderr, "sleeping\n");
- go_daemon();
- sleeping = 1; /* OPT_FOREGROUND means isatty() == 1! */
- break;
- default:
- break;
- }
-
- if (printmsg)
- fflush(stderr);
-}
-
-/*
- * Release the lease used to configure the interface.
- *
- * 1) Send DHCPRELEASE.
- * 2) Unconfigure address/routes/etc.
- * 3) Remove lease from database & write updated DB.
- */
-void
-release_lease(struct interface_info *ifi)
-{
- char buf[INET_ADDRSTRLEN];
- struct option_data *opt;
-
- if (ifi->configured == NULL || ifi->active == NULL)
- return; /* Nothing to release. */
- strlcpy(buf, inet_ntoa(ifi->configured->address), sizeof(buf));
-
- opt = &ifi->active->options[DHO_DHCP_SERVER_IDENTIFIER];
- if (opt->len == sizeof(in_addr_t))
- ifi->destination.s_addr = *(in_addr_t *)opt->data;
- else
- ifi->destination.s_addr = INADDR_BROADCAST;
-
- ifi->xid = arc4random();
- make_release(ifi, ifi->active);
- send_release(ifi);
-
- tell_unwind(NULL, ifi->flags);
-
- revoke_proposal(ifi->configured);
- imsg_flush(unpriv_ibuf);
-
- TAILQ_REMOVE(&ifi->lease_db, ifi->active, next);
- free_client_lease(ifi->active);
- ifi->active = NULL;
- write_lease_db(ifi);
-
- free(ifi->configured);
- ifi->configured = NULL;
- free(ifi->unwind_info);
- ifi->unwind_info = NULL;
-
- log_warnx("%s: %s RELEASED to %s", log_procname, buf,
- inet_ntoa(ifi->destination));
-}
-
-void
-propose_release(struct interface_info *ifi)
-{
- const struct timespec max_timeout = { 3, 0 };
- struct timespec now, stop, timeout;
- struct pollfd fds[1];
- struct rt_msghdr rtm;
- int nfds, routefd, rtfilter;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- timespecadd(&now, &max_timeout, &stop);
-
- if ((routefd = socket(AF_ROUTE, SOCK_RAW, AF_INET)) == -1)
- fatal("socket(AF_ROUTE, SOCK_RAW)");
-
- rtfilter = ROUTE_FILTER(RTM_PROPOSAL);
-
- if (setsockopt(routefd, AF_ROUTE, ROUTE_MSGFILTER,
- &rtfilter, sizeof(rtfilter)) == -1)
- fatal("setsockopt(ROUTE_MSGFILTER)");
- if (setsockopt(routefd, AF_ROUTE, ROUTE_TABLEFILTER, &ifi->rdomain,
- sizeof(ifi->rdomain)) == -1)
- fatal("setsockopt(ROUTE_TABLEFILTER)");
-
- memset(&rtm, 0, sizeof(rtm));
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_type = RTM_PROPOSAL;
- rtm.rtm_msglen = sizeof(rtm);
- rtm.rtm_tableid = ifi->rdomain;
- rtm.rtm_index = ifi->index;
- rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
- rtm.rtm_addrs = 0;
- rtm.rtm_flags = RTF_UP;
- rtm.rtm_flags |= RTF_PROTO2;
- rtm.rtm_seq = ifi->xid = arc4random();
-
- if (write(routefd, &rtm, sizeof(rtm)) == -1)
- fatal("write(routefd)");
- log_debug("%s: sent RTM_PROPOSAL to release lease", log_procname);
-
- while (quit == 0) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (timespeccmp(&now, &stop, >=))
- break;
- timespecsub(&stop, &now, &timeout);
- fds[0].fd = routefd;
- fds[0].events = POLLIN;
- nfds = ppoll(fds, 1, &timeout, NULL);
- if (nfds == -1) {
- if (errno == EINTR)
- continue;
- fatal("ppoll(routefd)");
- }
- if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0)
- fatalx("routefd: ERR|HUP|NVAL");
- if (nfds == 0 || (fds[0].revents & POLLIN) == 0)
- continue;
- routefd_handler(ifi, routefd);
- }
-}
+++ /dev/null
-.\" $OpenBSD: dhclient.conf.5,v 1.52 2022/03/31 17:27:19 naddy Exp $
-.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of The Internet Software Consortium nor the names
-.\" of its contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
-.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
-.\"
-.Dd $Mdocdate: March 31 2022 $
-.Dt DHCLIENT.CONF 5
-.Os
-.Sh NAME
-.Nm dhclient.conf
-.Nd DHCP client configuration file
-.Sh DESCRIPTION
-.Nm
-is the configuration file for
-.Xr dhclient 8 .
-It is a free-form ASCII text file made up of declarations, extra
-tabs and newlines for formatting purposes and comments.
-Keywords in the file are case-insensitive.
-Comments begin with the
-.Sq #
-character and extend to the end of the current line.
-.Sh PROTOCOL TIMING DECLARATIONS
-.Bl -tag -width Ds
-.It Ic backoff-cutoff Ar seconds ;
-Sets the maximum number of seconds to
-wait before retransmitting a packet.
-The default is 10 seconds.
-.It Ic initial-interval Ar seconds ;
-Sets the number of seconds between the first packet transmission
-and the first retransmission of the packet.
-The default is 1 second.
-.It Ic link-timeout Ar seconds ;
-Sets the number of seconds
-to wait for a lease before going into the background as a daemon.
-The default is 10 seconds.
-.It Ic reboot Ar seconds ;
-Sets the number of seconds to wait
-before giving up on reacquiring the previous lease, and how long
-to attempt unicast renewal requests before falling back to broadcast
-renewal requests.
-The default is 1 second.
-.It Ic retry Ar seconds ;
-Sets the number of seconds to wait before starting a new attempt to
-obtain a lease.
-The default is 1 second.
-.It Ic select-timeout Ar seconds ;
-Sets the number of seconds to wait for additional leases after the
-first lease arrives.
-After
-.Ic select-timeout
-seconds the best lease received will be selected.
-The default is 0 seconds, i.e. immediately use
-the first acceptable lease received.
-.It Ic timeout Ar seconds ;
-Sets the number of seconds to wait for a lease.
-If no lease is received, the first valid lease in
-.Xr dhclient.leases 5
-will be used.
-The default is 30 seconds.
-.El
-.Sh DHCP OPTION DECLARATIONS
-.Bl -tag -width Ds
-.It Ic append Ar option option-value ;
-Append
-.Ar option-value
-to the value of
-.Ar option
-in the lease.
-Each
-.Ic append
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic ignore ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.Pp
-If the option's data cannot be appended to, i.e. it has a fixed size,
-then
-.Ic append
-will be treated as
-.Ic default .
-.It Ic default Ar option option-value ;
-If no value for
-.Ar option
-is present in the lease, use
-.Ar option-value .
-Each
-.Ic default
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic ignore ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.It Ic ignore Op Ar option , ... ;
-Discard values provided for the listed options.
-.Ic ignore
-statements are cumulative, except that an empty
-list will remove all previously specified options.
-Each
-.Ic ignore
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.It Ic prepend Ar option option-value ;
-Prepend
-.Ar option-value
-to the value of
-.Ar option
-in the lease.
-Each
-.Ic prepend
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic ignore ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.Pp
-If the option's data cannot be prepended to, i.e. it has a fixed size,
-then
-.Ic prepend
-will be treated as
-.Ic supersede .
-.It Ic request Op Ar option , ... ;
-Ask that any lease contain values
-for the listed options.
-.Ic request
-statements are cumulative, except that an empty
-list will remove all previously specified options.
-The default is to request the options
-bootfile-name,
-broadcast-address,
-classless-static-routes,
-host-name,
-domain-name,
-domain-name-servers,
-domain-search,
-routers,
-subnet-mask,
-tftp-server-name
-and
-time-offset.
-.It Ic require Op Ar option , ... ;
-Discard leases that do not contain the listed options.
-.Ic require
-statements are cumulative, except that an empty
-list will remove all previously specified options.
-The default is to require the option subnet-mask.
-.It Ic send Ar option option-value ;
-Include
-.Ar option-value
-in requests for a lease.
-To include multiple options in requests,
-.Ic send
-can be used multiple times.
-.It Ic supersede Ar option option-value ;
-Use
-.Ar option-value
-for the given
-.Ar option
-regardless of the value in the lease.
-Each
-.Ic supersede
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic ignore ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.It Ic uselease Op Ar option , ... ;
-Use the unmodified values provided in the lease for
-any specified
-.Ar option .
-.Ic uselease
-statements are cumulative.
-If no
-.Ar option
-is specified, all lease option values will be used unmodified.
-.Ic uselease
-for
-.Ar option
-overrides any previous
-.Ic append ,
-.Ic default ,
-.Ic ignore ,
-.Ic prepend
-or
-.Ic supersede
-for
-.Ar option .
-.El
-.Sh OTHER DECLARATIONS
-.Bl -tag -width Ds
-.It Ic filename Ar path ;
-Use
-.Ar path
-instead of the
-.Ic file
-field of the DHCP offer when binding a lease.
-.It Ic fixed-address Ar ip-address ;
-Use
-.Ar ip-address
-instead of the
-.Ic yiaddr
-field of the DHCP offer when binding a lease.
-.It Ic interface Qo Ar name Qc No { Ar declaration ; ... ; No }
-Apply any
-.Ar declaration
-only to the named interface.
-.It Ic reject Ar ip-address ;
-Discard leases from the specified address.
-If more than one
-.Ic reject
-is present, all leases from any of the
-addresses will be discarded.
-.It Ic next-server Ar ip-address ;
-Use
-.Ar ip-address
-instead of the
-.Ic siaddr
-field of the DHCP offer when binding a lease.
-.It Ic server-name Ar host ;
-Use
-.Ar host
-instead of the
-.Ic sname
-field of the DHCP offer when binding a lease.
-.El
-.Sh FILES
-.Bl -tag -width /etc/examples/dhclient.conf -compact
-.It Pa /etc/dhclient.conf
-.It Pa /etc/examples/dhclient.conf
-.El
-.Sh SEE ALSO
-.Xr dhclient.leases 5 ,
-.Xr dhcp-options 5 ,
-.Xr dhcpd.conf 5 ,
-.Xr dhclient 8 ,
-.Xr dhcpd 8
+++ /dev/null
-.\" $OpenBSD: dhclient.leases.5,v 1.14 2017/12/18 14:17:58 krw Exp $
-.\"
-.\" Copyright (c) 1997 The Internet Software Consortium.
-.\" All rights reserved.
-.\"
-.\" Redistribution and use in source and binary forms, with or without
-.\" modification, are permitted provided that the following conditions
-.\" are met:
-.\"
-.\" 1. Redistributions of source code must retain the above copyright
-.\" notice, this list of conditions and the following disclaimer.
-.\" 2. Redistributions in binary form must reproduce the above copyright
-.\" notice, this list of conditions and the following disclaimer in the
-.\" documentation and/or other materials provided with the distribution.
-.\" 3. Neither the name of The Internet Software Consortium nor the names
-.\" of its contributors may be used to endorse or promote products derived
-.\" from this software without specific prior written permission.
-.\"
-.\" THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
-.\" CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
-.\" INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-.\" DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
-.\" CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-.\" SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-.\" LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
-.\" USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
-.\" ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
-.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
-.\" SUCH DAMAGE.
-.\"
-.\" This software has been written for the Internet Software Consortium
-.\" by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
-.\" Enterprises. To learn more about the Internet Software Consortium,
-.\" see ``http://www.isc.org/isc''. To learn more about Vixie
-.\" Enterprises, see ``http://www.vix.com''.
-.\"
-.Dd $Mdocdate: December 18 2017 $
-.Dt DHCLIENT.LEASES 5
-.Os
-.Sh NAME
-.Nm dhclient.leases
-.Nd DHCP client lease database
-.Sh DESCRIPTION
-.Xr dhclient 8
-keeps a persistent database of leases that it has acquired that are still
-valid.
-The database is a free-form ASCII file containing one valid declaration
-per lease.
-The file is written as a log, so the last declaration is the most recent
-lease obtained.
-.Pp
-The lease file is named
-.Pa /var/db/dhclient.leases . Ns Aq Ar IFNAME ,
-where
-.Qq IFNAME
-represents the network interface
-.Xr dhclient 8
-acquired the lease on.
-For example, if
-.Xr dhclient 8
-is configured for the em0 network device,
-the lease file will be named
-.Pa /var/db/dhclient.leases.em0 ,
-.Pp
-A lease statement has the format
-.Pp
-.D1 Ic lease No { Ar lease-declaration ; ... ; No }
-.Pp
-Where
-.Ar lease\-declaration
-is one of:
-.Pp
-.Bl -tag -width Ds -compact
-.It Ic bootp
-The lease was acquired using the
-BOOTP protocol rather than the DHCP protocol.
-.Pp
-.It Ic epoch
-The
-.Xr time 3
-when the lease was obtained.
-This value is used to convert the values of the DHCP options
-.Ic dhcp-lease-time ,
-.Ic dhcp-renewal-time ,
-and
-.Ic dhcp-rebinding-time
-to times.
-A value of 0 will cause
-.Ic epoch
-to be set to the current time when
-.Nm
-is processed.
-.Pp
-.It Ic expire Ar date
-.It Ic rebind Ar date
-.It Ic renew Ar date
-.Ic expire
-is when
-.Xr dhclient 8
-will no longer use the lease to configure the interface.
-.Ic rebind
-is when
-.Xr dhclient 8
-will begin trying to renew the lease with broadcasts to any server.
-.Ic renew
-is when
-.Xr dhclient 8
-will begin trying to renew the lease with unicasts to the originating server.
-.Pp
-Dates are specified in accordance with the
-.Xr strptime 3
-format:
-.Pp
-.D1 %w %Y/%m/%d \&%T UTC
-.Pp
-For example:
-.Pp
-.Dl renew 1 2017/10/16 14:03:49 UTC
-.Pp
-.Ic expire ,
-.Ic rebind ,
-.Ic renew
-are just comments that are ignored when processing
-.Nm .
-The values used by
-.Xr dhclient 8
-are always recalculated based on
-.Ic epoch
-when
-.Nm
-is processed.
-.Pp
-.It Ic filename Qq Ar string
-The boot filename.
-.Pp
-.It Ic fixed-address Ar ip-address
-The IPv4 address of the lease.
-This is required for all lease statements.
-The IPv4 address is specified as a dotted quad (e.g. 12.34.56.78).
-.Pp
-.It Ic next-server Ar ip-address
-The IPv4 address of the boot server.
-The IPv4 address is specified as a dotted quad (e.g. 12.34.56.78).
-.Pp
-.It Ic option Ar option option-value
-The value of
-.Ar option .
-DHCP options are described in
-.Xr dhcp-options 5 .
-.Pp
-.It Ic server-name Qq Ar string
-The name of the boot server.
-.Pp
-.It Ic ssid Qq Ar string
-The SSID to which the lease applies.
-.El
-.Sh FILES
-.Bl -tag -width "/var/db/dhclient.leases.IFNAME "
-.It Pa /var/db/dhclient.leases . Ns Aq Ar IFNAME
-Persistent database of leases for
-.Aq Ar IFNAME .
-.El
-.Sh SEE ALSO
-.Xr dhclient.conf 5 ,
-.Xr dhcp-options 5 ,
-.Xr dhcpd.conf 5 ,
-.Xr dhclient 8 ,
-.Xr dhcpd 8
+++ /dev/null
-/* $OpenBSD: dhcp.h,v 1.21 2017/07/24 16:17:35 krw Exp $ */
-
-/* Protocol structures. */
-
-/*
- * Copyright (c) 1995, 1996 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#define DHCP_UDP_OVERHEAD (20 + /* IP header */ \
- 8) /* UDP header */
-#define DHCP_SNAME_LEN 64
-#define DHCP_FILE_LEN 128
-#define DHCP_FIXED_NON_UDP 236
-#define DHCP_FIXED_LEN (DHCP_FIXED_NON_UDP + DHCP_UDP_OVERHEAD)
- /* Everything but options. */
-#define DHCP_MTU_MAX 1500
-#define DHCP_OPTION_LEN (DHCP_MTU_MAX - DHCP_FIXED_LEN)
-
-/* Respect historical limits on 'search' line in resolv.conf(5) */
-#define DHCP_DOMAIN_SEARCH_LEN 1024
-#define DHCP_DOMAIN_SEARCH_CNT 6
-
-#define BOOTP_MIN_LEN 300
-
-struct dhcp_packet {
- uint8_t op; /* Message opcode/type */
- uint8_t htype; /* Hardware addr type (see net/if_types.h) */
- uint8_t hlen; /* Hardware addr length */
- uint8_t hops; /* Number of relay agent hops from client */
- uint32_t xid; /* Transaction ID */
- uint16_t secs; /* Seconds since client started looking */
- uint16_t flags; /* Flag bits */
- struct in_addr ciaddr; /* Client IP address (if already in use) */
- struct in_addr yiaddr; /* Client IP address */
- struct in_addr siaddr; /* IP address of next server to talk to */
- struct in_addr giaddr; /* DHCP relay agent IP address */
- unsigned char chaddr[16]; /* Client hardware address */
- char sname[DHCP_SNAME_LEN]; /* Server name */
- char file[DHCP_FILE_LEN]; /* Boot filename */
- unsigned char options[DHCP_OPTION_LEN];
- /* Optional parameters
- (actual length dependent on MTU). */
-};
-
-/* BOOTP (rfc951) message types */
-#define BOOTREQUEST 1
-#define BOOTREPLY 2
-
-/* Possible values for flags field. */
-#define BOOTP_BROADCAST 32768L
-
-/* Possible values for hardware type (htype) field. */
-#define HTYPE_ETHER 1 /* Ethernet */
-#define HTYPE_IPSEC_TUNNEL 31 /* IPsec Tunnel (RFC3456) */
-
-/*
- * Magic cookie validating dhcp options field (and bootp vendor
- * extensions field).
- */
-#define DHCP_OPTIONS_COOKIE "\143\202\123\143"
-#define DHCP_OPTIONS_COOKIE_LEN 4
-#define DHCP_OPTIONS_MESSAGE_TYPE "\065\001\000"
-
-/* DHCP Option codes: */
-#define DHO_PAD 0
-#define DHO_SUBNET_MASK 1
-#define DHO_TIME_OFFSET 2
-#define DHO_ROUTERS 3
-#define DHO_TIME_SERVERS 4
-#define DHO_NAME_SERVERS 5
-#define DHO_DOMAIN_NAME_SERVERS 6
-#define DHO_LOG_SERVERS 7
-#define DHO_COOKIE_SERVERS 8
-#define DHO_LPR_SERVERS 9
-#define DHO_IMPRESS_SERVERS 10
-#define DHO_RESOURCE_LOCATION_SERVERS 11
-#define DHO_HOST_NAME 12
-#define DHO_BOOT_SIZE 13
-#define DHO_MERIT_DUMP 14
-#define DHO_DOMAIN_NAME 15
-#define DHO_SWAP_SERVER 16
-#define DHO_ROOT_PATH 17
-#define DHO_EXTENSIONS_PATH 18
-#define DHO_IP_FORWARDING 19
-#define DHO_NON_LOCAL_SOURCE_ROUTING 20
-#define DHO_POLICY_FILTER 21
-#define DHO_MAX_DGRAM_REASSEMBLY 22
-#define DHO_DEFAULT_IP_TTL 23
-#define DHO_PATH_MTU_AGING_TIMEOUT 24
-#define DHO_PATH_MTU_PLATEAU_TABLE 25
-#define DHO_INTERFACE_MTU 26
-#define DHO_ALL_SUBNETS_LOCAL 27
-#define DHO_BROADCAST_ADDRESS 28
-#define DHO_PERFORM_MASK_DISCOVERY 29
-#define DHO_MASK_SUPPLIER 30
-#define DHO_ROUTER_DISCOVERY 31
-#define DHO_ROUTER_SOLICITATION_ADDRESS 32
-#define DHO_STATIC_ROUTES 33
-#define DHO_TRAILER_ENCAPSULATION 34
-#define DHO_ARP_CACHE_TIMEOUT 35
-#define DHO_IEEE802_3_ENCAPSULATION 36
-#define DHO_DEFAULT_TCP_TTL 37
-#define DHO_TCP_KEEPALIVE_INTERVAL 38
-#define DHO_TCP_KEEPALIVE_GARBAGE 39
-#define DHO_NIS_DOMAIN 40
-#define DHO_NIS_SERVERS 41
-#define DHO_NTP_SERVERS 42
-#define DHO_VENDOR_ENCAPSULATED_OPTIONS 43
-#define DHO_NETBIOS_NAME_SERVERS 44
-#define DHO_NETBIOS_DD_SERVER 45
-#define DHO_NETBIOS_NODE_TYPE 46
-#define DHO_NETBIOS_SCOPE 47
-#define DHO_FONT_SERVERS 48
-#define DHO_X_DISPLAY_MANAGER 49
-#define DHO_DHCP_REQUESTED_ADDRESS 50
-#define DHO_DHCP_LEASE_TIME 51
-#define DHO_DHCP_OPTION_OVERLOAD 52
-#define DHO_DHCP_MESSAGE_TYPE 53
-#define DHO_DHCP_SERVER_IDENTIFIER 54
-#define DHO_DHCP_PARAMETER_REQUEST_LIST 55
-#define DHO_DHCP_MESSAGE 56
-#define DHO_DHCP_MAX_MESSAGE_SIZE 57
-#define DHO_DHCP_RENEWAL_TIME 58
-#define DHO_DHCP_REBINDING_TIME 59
-#define DHO_DHCP_CLASS_IDENTIFIER 60
-#define DHO_DHCP_CLIENT_IDENTIFIER 61
-#define DHO_NISPLUS_DOMAIN 64
-#define DHO_NISPLUS_SERVERS 65
-#define DHO_TFTP_SERVER 66
-#define DHO_BOOTFILE_NAME 67
-#define DHO_MOBILE_IP_HOME_AGENT 68
-#define DHO_SMTP_SERVER 69
-#define DHO_POP_SERVER 70
-#define DHO_NNTP_SERVER 71
-#define DHO_WWW_SERVER 72
-#define DHO_FINGER_SERVER 73
-#define DHO_IRC_SERVER 74
-#define DHO_STREETTALK_SERVER 75
-#define DHO_STREETTALK_DIRECTORY_ASSISTANCE_SERVER 76
-#define DHO_DHCP_USER_CLASS_ID 77
-#define DHO_RELAY_AGENT_INFORMATION 82
-#define DHO_NDS_SERVERS 85
-#define DHO_NDS_TREE_NAME 86
-#define DHO_NDS_CONTEXT 87
-#define DHO_DOMAIN_SEARCH 119
-#define DHO_CLASSLESS_STATIC_ROUTES 121
-#define DHO_TFTP_CONFIG_FILE 144
-#define DHO_VOIP_CONFIGURATION_SERVER 150
-#define DHO_CLASSLESS_MS_STATIC_ROUTES 249
-#define DHO_AUTOPROXY_SCRIPT 252
-#define DHO_END 255
-#define DHO_COUNT 256 /* # of DHCP options */
-
-/* DHCP message types. */
-#define DHCPDISCOVER 1
-#define DHCPOFFER 2
-#define DHCPREQUEST 3
-#define DHCPDECLINE 4
-#define DHCPACK 5
-#define DHCPNAK 6
-#define DHCPRELEASE 7
-#define DHCPINFORM 8
-
-/* Relay Agent Information sub-options */
-#define RAI_CIRCUIT_ID 1
-#define RAI_REMOTE_ID 2
-#define RAI_AGENT_ID 3
+++ /dev/null
-/* $OpenBSD: dhcpd.h,v 1.299 2021/03/28 16:23:05 krw Exp $ */
-
-/*
- * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#define LOCAL_PORT 68
-#define REMOTE_PORT 67
-#define TERMINATE 1
-#define RESTART 2
-#define DB_TIMEFMT "%w %Y/%m/%d %T UTC"
-#define RT_BUF_SIZE 2048
-
-struct option_data {
- unsigned int len;
- uint8_t *data;
-};
-
-struct reject_elem {
- TAILQ_ENTRY(reject_elem) next;
- struct in_addr addr;
-};
-
-struct client_lease {
- TAILQ_ENTRY(client_lease) next;
- time_t epoch;
- struct in_addr address;
- struct in_addr next_server;
- char *server_name;
- char *filename;
- char ssid[32];
- uint8_t ssid_len;
- struct option_data options[DHO_COUNT];
-};
-#define BOOTP_LEASE(l) ((l)->options[DHO_DHCP_MESSAGE_TYPE].len == 0)
-
-/* Possible states in which the client can be. */
-enum dhcp_state {
- S_PREBOOT,
- S_REBOOTING,
- S_INIT,
- S_SELECTING,
- S_REQUESTING,
- S_BOUND,
- S_RENEWING
-};
-
-enum actions {
- ACTION_USELEASE,
- ACTION_DEFAULT,
- ACTION_SUPERSEDE,
- ACTION_PREPEND,
- ACTION_APPEND,
- ACTION_IGNORE
-};
-
-TAILQ_HEAD(client_lease_tq, client_lease);
-
-struct client_config {
- struct option_data defaults[DHO_COUNT];
- enum actions default_actions[DHO_COUNT];
- struct in_addr address;
- struct in_addr next_server;
- struct option_data send_options[DHO_COUNT];
- uint8_t required_options[DHO_COUNT];
- uint8_t requested_options[DHO_COUNT];
- int requested_option_count;
- int required_option_count;
- time_t offer_interval;
- time_t initial_interval;
- time_t link_interval;
- time_t retry_interval;
- time_t select_interval;
- time_t reboot_interval;
- time_t backoff_cutoff;
- TAILQ_HEAD(, reject_elem) reject_list;
- char *filename;
- char *server_name;
-};
-
-
-struct interface_info {
- struct ether_addr hw_address;
- char name[IFNAMSIZ];
- char ssid[32];
- uint8_t ssid_len;
- int bpffd; /* bpf - reading & broadcast writing*/
- int udpfd; /* udp - unicast writing */
- unsigned char *rbuf;
- size_t rbuf_max;
- int errors;
- uint16_t index;
- int link_state;
- int rdomain;
- int flags;
-#define IFI_IN_CHARGE 0x01
- uint32_t mtu;
- struct dhcp_packet recv_packet;
- struct dhcp_packet sent_packet;
- int sent_packet_length;
- uint32_t xid;
- struct timespec timeout;
- struct timespec reboot_timeout;
- struct timespec expiry;
- struct timespec rebind;
- struct timespec renew;
- void (*timeout_func)(struct interface_info *);
- uint16_t secs;
- struct timespec first_sending;
- struct timespec link_timeout;
- struct timespec offer_timeout;
- struct timespec select_timeout;
- enum dhcp_state state;
- struct in_addr destination;
- time_t interval;
- struct in_addr requested_address;
- struct client_lease *active;
- struct client_lease *offer;
- char *offer_src;
- struct proposal *configured;
- struct unwind_info *unwind_info;
- struct client_lease_tq lease_db;
-};
-
-#define _PATH_DHCLIENT_CONF "/etc/dhclient.conf"
-#define _PATH_LEASE_DB "/var/db/dhclient.leases"
-
-/* options.c */
-int pack_options(unsigned char *, int,
- struct option_data *);
-struct option_data *unpack_options(struct dhcp_packet *);
-char *pretty_print_option(unsigned int, struct option_data *,
- int);
-char *pretty_print_string(unsigned char *, size_t, int);
-char *code_to_name(int);
-char *code_to_format(int);
-int code_to_action(int, int);
-int name_to_code(char *);
-void merge_option_data(char *, struct option_data *,
- struct option_data *, struct option_data *);
-
-/* conflex.c */
-extern int lexline, lexchar;
-extern char *token_line, *tlname;
-
-void new_parse(char *);
-int next_token(char **, FILE *);
-int peek_token(char **, FILE *);
-
-/* parse.c */
-void skip_to_semi(FILE *);
-int parse_semi(FILE *);
-int parse_string(FILE *, char **);
-int parse_ip_addr(FILE *, struct in_addr *);
-int parse_cidr(FILE *, unsigned char *);
-int parse_number(FILE *, long long *, long long, long long);
-int parse_boolean(FILE *, unsigned char *);
-void parse_warn(char *);
-
-/* bpf.c */
-int get_bpf_sock(char *);
-int get_udp_sock(int);
-int configure_bpf_sock(int);
-ssize_t send_packet(struct interface_info *, struct in_addr,
- struct in_addr, const char *);
-ssize_t receive_packet(unsigned char *, unsigned char *,
- struct sockaddr_in *, struct ether_addr *, struct dhcp_packet *);
-
-/* dispatch.c */
-void dispatch(struct interface_info *, int);
-void set_timeout( struct interface_info *, time_t,
- void (*)(struct interface_info *));
-void cancel_timeout(struct interface_info *);
-
-/* dhclient.c */
-extern char *path_dhclient_conf;
-extern char *path_lease_db;
-extern char *log_procname;
-extern struct client_config *config;
-extern struct imsgbuf *unpriv_ibuf;
-extern int quit;
-extern int cmd_opts;
-#define OPT_NOACTION 0x01
-#define OPT_VERBOSE 0x02
-#define OPT_FOREGROUND 0x04
-#define OPT_RELEASE 0x08
-
-void dhcpoffer(struct interface_info *, struct option_data *,
- const char *);
-void dhcpack(struct interface_info *, struct option_data *,
- const char *);
-void dhcpnak(struct interface_info *, const char *);
-void bootreply(struct interface_info *, struct option_data *,
- const char *);
-void free_client_lease(struct client_lease *);
-void routefd_handler(struct interface_info *, int);
-void state_preboot(struct interface_info *);
-char *rfc1035_as_string(unsigned char *, size_t);
-
-/* packet.c */
-void assemble_eh_header(struct ether_addr, struct ether_header *);
-ssize_t decode_udp_ip_header(unsigned char *, uint32_t,
- struct sockaddr_in *);
-uint32_t checksum(unsigned char *, uint32_t, uint32_t);
-uint32_t wrapsum(uint32_t);
-
-/* clparse.c */
-void init_config(void);
-void read_conf(char *, uint8_t *, struct ether_addr *);
-void read_lease_db(struct client_lease_tq *);
-
-/* kroute.c */
-unsigned int extract_route(uint8_t *, unsigned int, in_addr_t *,
- in_addr_t *, in_addr_t *);
-void write_resolv_conf(void);
-
-void propose(struct proposal *);
-void revoke_proposal(struct proposal *);
-
-void tell_unwind(struct unwind_info *, int);
+++ /dev/null
-/* $OpenBSD: dhctoken.h,v 1.16 2019/01/26 23:26:20 krw Exp $ */
-
-/* Tokens for config file lexer and parser. */
-
-/*
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#define TOK_FIRST_TOKEN TOK_FILENAME
-#define TOK_FILENAME 257
-#define TOK_FIXED_ADDR 259
-#define TOK_OPTION 260
-#define TOK_STRING 262
-#define TOK_NUMBER 263
-#define TOK_NUMBER_OR_NAME 264
-#define TOK_NAME 265
-#define TOK_LEASE 266
-#define TOK_SERVER_NAME 267
-#define TOK_SEND 269
-#define TOK_REQUEST 270
-#define TOK_REQUIRE 271
-#define TOK_TIMEOUT 272
-#define TOK_RETRY 273
-#define TOK_SELECT_TIMEOUT 274
-#define TOK_NEXT_SERVER 275
-#define TOK_INTERFACE 276
-#define TOK_RENEW 277
-#define TOK_REBIND 278
-#define TOK_EXPIRE 279
-#define TOK_BOOTP 280
-#define TOK_DEFAULT 282
-#define TOK_REBOOT 286
-#define TOK_BACKOFF_CUTOFF 287
-#define TOK_INITIAL_INTERVAL 288
-#define TOK_SUPERSEDE 289
-#define TOK_APPEND 290
-#define TOK_PREPEND 291
-#define TOK_REJECT 292
-#define TOK_LINK_TIMEOUT 294
-#define TOK_IGNORE 295
-#define TOK_SSID 296
-#define TOK_EPOCH 297
-#define TOK_USELEASE 298
-
-#define is_identifier(x) ((x) >= TOK_FIRST_TOKEN && \
- (x) != TOK_STRING && \
- (x) != TOK_NUMBER && \
- (x) != EOF)
+++ /dev/null
-/* $OpenBSD: dispatch.c,v 1.172 2021/03/28 17:25:21 krw Exp $ */
-
-/*
- * Copyright 2004 Henning Brauer <henning@openbsd.org>
- * Copyright (c) 1995, 1996, 1997, 1998, 1999
- * The Internet Software Consortium. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/ioctl.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-
-#include <net/if.h>
-#include <net/if_arp.h>
-#include <net/if_media.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <arpa/inet.h>
-
-#include <errno.h>
-#include <imsg.h>
-#include <limits.h>
-#include <poll.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-#include "privsep.h"
-
-
-void bpffd_handler(struct interface_info *);
-void dhcp_packet_dispatch(struct interface_info *, struct sockaddr_in *,
- struct ether_addr *);
-void flush_unpriv_ibuf(void);
-
-/*
- * Loop waiting for packets, timeouts or routing messages.
- */
-void
-dispatch(struct interface_info *ifi, int routefd)
-{
- const struct timespec link_intvl = {config->link_interval, 0};
- struct pollfd fds[3];
- struct timespec timeout;
- struct timespec *ts;
- void (*func)(struct interface_info *);
- int nfds;
-
- log_debug("%s: link is %s", log_procname,
- LINK_STATE_IS_UP(ifi->link_state) ? "up" : "down");
-
- while (quit == 0 || quit == RESTART) {
- if (quit == RESTART) {
- quit = 0;
- clock_gettime(CLOCK_MONOTONIC, &ifi->link_timeout);
- timespecadd(&ifi->link_timeout, &link_intvl, &ifi->link_timeout);
- free(ifi->configured);
- ifi->configured = NULL;
- free(ifi->unwind_info);
- ifi->unwind_info = NULL;
- ifi->state = S_PREBOOT;
- state_preboot(ifi);
- }
- if (timespecisset(&ifi->timeout)) {
- clock_gettime(CLOCK_MONOTONIC, &timeout);
- if (timespeccmp(&timeout, &ifi->timeout, >=)) {
- func = ifi->timeout_func;
- cancel_timeout(ifi);
- (*(func))(ifi);
- continue;
- }
- timespecsub(&ifi->timeout, &timeout, &timeout);
- ts = &timeout;
- } else
- ts = NULL;
-
- /*
- * Set up the descriptors to be polled.
- *
- * fds[0] == bpf socket for incoming packets
- * fds[1] == routing socket for incoming RTM messages
- * fds[2] == imsg socket to privileged process
- */
- fds[0].fd = ifi->bpffd;
- fds[1].fd = routefd;
- fds[2].fd = unpriv_ibuf->fd;
- fds[0].events = fds[1].events = fds[2].events = POLLIN;
-
- if (unpriv_ibuf->w.queued)
- fds[2].events |= POLLOUT;
-
- nfds = ppoll(fds, 3, ts, NULL);
- if (nfds == -1) {
- if (errno == EINTR)
- continue;
- log_warn("%s: ppoll(bpffd, routefd, unpriv_ibuf)",
- log_procname);
- break;
- }
-
- if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
- log_debug("%s: bpffd: ERR|HUP|NVAL", log_procname);
- break;
- }
- if ((fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
- log_debug("%s: routefd: ERR|HUP|NVAL", log_procname);
- break;
- }
- if ((fds[2].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
- log_debug("%s: unpriv_ibuf: ERR|HUP|NVAL", log_procname);
- break;
- }
-
- if (nfds == 0)
- continue;
-
- if ((fds[0].revents & POLLIN) != 0)
- bpffd_handler(ifi);
- if ((fds[1].revents & POLLIN) != 0)
- routefd_handler(ifi, routefd);
- if ((fds[2].revents & POLLOUT) != 0)
- flush_unpriv_ibuf();
- if ((fds[2].revents & POLLIN) != 0)
- break;
- }
-}
-
-void
-bpffd_handler(struct interface_info *ifi)
-{
- struct sockaddr_in from;
- struct ether_addr hfrom;
- unsigned char *next, *lim;
- ssize_t n;
-
- n = read(ifi->bpffd, ifi->rbuf, ifi->rbuf_max);
- if (n == -1) {
- log_warn("%s: read(bpffd)", log_procname);
- ifi->errors++;
- if (ifi->errors > 20)
- fatalx("too many read(bpffd) failures");
- return;
- }
- ifi->errors = 0;
-
- lim = ifi->rbuf + n;
- for (next = ifi->rbuf; quit == 0 && n > 0; next += n) {
- n = receive_packet(next, lim, &from, &hfrom, &ifi->recv_packet);
- if (n > 0)
- dhcp_packet_dispatch(ifi, &from, &hfrom);
- }
-}
-
-void
-dhcp_packet_dispatch(struct interface_info *ifi, struct sockaddr_in *from,
- struct ether_addr *hfrom)
-{
- struct in_addr ifrom;
- struct dhcp_packet *packet = &ifi->recv_packet;
- struct reject_elem *ap;
- struct option_data *options;
- char *src;
- int i, rslt;
-
- ifrom.s_addr = from->sin_addr.s_addr;
-
- if (packet->hlen != ETHER_ADDR_LEN) {
- log_debug("%s: discarding packet with hlen == %u", log_procname,
- packet->hlen);
- return;
- } else if (memcmp(&ifi->hw_address, packet->chaddr,
- sizeof(ifi->hw_address)) != 0) {
- log_debug("%s: discarding packet with chaddr == %s",
- log_procname,
- ether_ntoa((struct ether_addr *)packet->chaddr));
- return;
- }
-
- if (ifi->xid != packet->xid) {
- log_debug("%s: discarding packet with XID != %u (%u)",
- log_procname, ifi->xid, packet->xid);
- return;
- }
-
- TAILQ_FOREACH(ap, &config->reject_list, next)
- if (ifrom.s_addr == ap->addr.s_addr) {
- log_debug("%s: discarding packet from address on reject "
- "list (%s)", log_procname, inet_ntoa(ifrom));
- return;
- }
-
- options = unpack_options(&ifi->recv_packet);
-
- /*
- * RFC 6842 says if the server sends a client identifier
- * that doesn't match then the packet must be dropped.
- */
- i = DHO_DHCP_CLIENT_IDENTIFIER;
- if ((options[i].len != 0) &&
- ((options[i].len != config->send_options[i].len) ||
- memcmp(options[i].data, config->send_options[i].data,
- options[i].len) != 0)) {
- log_debug("%s: discarding packet with client-identifier %s'",
- log_procname, pretty_print_option(i, &options[i], 0));
- return;
- }
-
- rslt = asprintf(&src, "%s (%s)", inet_ntoa(ifrom), ether_ntoa(hfrom));
- if (rslt == -1)
- fatal("src");
-
- i = DHO_DHCP_MESSAGE_TYPE;
- if (options[i].data != NULL) {
- /* Always try a DHCP packet, even if a bad option was seen. */
- switch (options[i].data[0]) {
- case DHCPOFFER:
- dhcpoffer(ifi, options, src);
- break;
- case DHCPNAK:
- dhcpnak(ifi, src);
- break;
- case DHCPACK:
- dhcpack(ifi, options, src);
- break;
- default:
- log_debug("%s: discarding DHCP packet of unknown type "
- "(%d)", log_procname, options[i].data[0]);
- break;
- }
- } else if (packet->op == BOOTREPLY) {
- bootreply(ifi, options, src);
- } else {
- log_debug("%s: discarding packet which is neither DHCP nor "
- "BOOTP", log_procname);
- }
-
- free(src);
-}
-
-/*
- * flush_unpriv_ibuf stuffs queued messages into the imsg socket.
- */
-void
-flush_unpriv_ibuf(void)
-{
- while (unpriv_ibuf->w.queued) {
- if (msgbuf_write(&unpriv_ibuf->w) <= 0) {
- if (errno == EAGAIN)
- break;
- if (quit == 0)
- quit = TERMINATE;
- if (errno != EPIPE && errno != 0)
- log_warn("%s: msgbuf_write(unpriv_ibuf)",
- log_procname);
- break;
- }
- }
-}
-
-void
-set_timeout(struct interface_info *ifi, time_t secs,
- void (*where)(struct interface_info *))
-{
- struct timespec now;
-
- clock_gettime(CLOCK_MONOTONIC, &now);
- timespecclear(&ifi->timeout);
- ifi->timeout.tv_sec = secs;
- timespecadd(&ifi->timeout, &now, &ifi->timeout);
- ifi->timeout_func = where;
-}
-
-void
-cancel_timeout(struct interface_info *ifi)
-{
- timespecclear(&ifi->timeout);
- ifi->timeout_func = NULL;
-}
+++ /dev/null
-/* $OpenBSD: kroute.c,v 1.197 2021/03/28 17:25:21 krw Exp $ */
-
-/*
- * Copyright 2012 Kenneth R Westerback <krw@openbsd.org>
- *
- * 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 <sys/ioctl.h>
-#include <sys/queue.h>
-#include <sys/socket.h>
-#include <sys/stat.h>
-#include <sys/sysctl.h>
-
-#include <arpa/inet.h>
-
-#include <net/if.h>
-#include <net/if_types.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <errno.h>
-#include <fcntl.h>
-#include <ifaddrs.h>
-#include <imsg.h>
-#include <limits.h>
-#include <poll.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-#include "privsep.h"
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
-#define CIDR_MAX_BITS 32
-
-int delete_addresses(char *, int, struct in_addr, struct in_addr);
-void set_address(char *, int, struct in_addr, struct in_addr);
-void delete_address(char *, int, struct in_addr);
-
-char *get_routes(int, size_t *);
-void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
-unsigned int route_pos(struct rt_msghdr *, uint8_t *, unsigned int,
- struct in_addr);
-void flush_routes(int, int, int, uint8_t *, unsigned int,
- struct in_addr);
-void discard_route(uint8_t *, unsigned int);
-void add_route(char *, int, int, struct in_addr, struct in_addr,
- struct in_addr, struct in_addr, int);
-void set_routes(char *, int, int, int, struct in_addr,
- struct in_addr, uint8_t *, unsigned int);
-
-int default_route_index(int, int);
-char *resolv_conf_tail(void);
-char *set_resolv_conf(char *, char *, struct unwind_info *);
-
-void set_mtu(char *, int, uint16_t);
-
-/*
- * delete_addresses() removes all inet addresses on the named interface, except
- * for newaddr/newnetmask.
- *
- * If newaddr/newmask is already present, return 1, else 0.
- */
-int
-delete_addresses(char *name, int ioctlfd, struct in_addr newaddr,
- struct in_addr newnetmask)
-{
- struct in_addr addr, netmask;
- struct ifaddrs *ifap, *ifa;
- int found;
-
- if (getifaddrs(&ifap) == -1)
- fatal("getifaddrs");
-
- found = 0;
- for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
- if ((ifa->ifa_flags & IFF_LOOPBACK) != 0 ||
- (ifa->ifa_flags & IFF_POINTOPOINT) != 0 ||
- ((ifa->ifa_flags & IFF_UP) == 0) ||
- (ifa->ifa_addr->sa_family != AF_INET) ||
- (strcmp(name, ifa->ifa_name) != 0))
- continue;
-
- memcpy(&addr,
- &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr,
- sizeof(addr));
- memcpy(&netmask,
- &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr,
- sizeof(netmask));
-
- if (addr.s_addr == newaddr.s_addr &&
- netmask.s_addr == newnetmask.s_addr) {
- found = 1;
- } else {
- delete_address(name, ioctlfd, addr);
- }
- }
-
- freeifaddrs(ifap);
- return found;
-}
-
-/*
- * set_address() is the equivalent of
- *
- * ifconfig <if> inet <addr> netmask <mask> broadcast <addr>
- */
-void
-set_address(char *name, int ioctlfd, struct in_addr addr,
- struct in_addr netmask)
-{
- struct ifaliasreq ifaliasreq;
- struct sockaddr_in *in;
-
- if (delete_addresses(name, ioctlfd, addr, netmask) == 1)
- return;
-
- memset(&ifaliasreq, 0, sizeof(ifaliasreq));
- strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name));
-
- /* The actual address in ifra_addr. */
- in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
- in->sin_family = AF_INET;
- in->sin_len = sizeof(ifaliasreq.ifra_addr);
- in->sin_addr.s_addr = addr.s_addr;
-
- /* And the netmask in ifra_mask. */
- in = (struct sockaddr_in *)&ifaliasreq.ifra_mask;
- in->sin_family = AF_INET;
- in->sin_len = sizeof(ifaliasreq.ifra_mask);
- in->sin_addr.s_addr = netmask.s_addr;
-
- /* No need to set broadcast address. Kernel can figure it out. */
-
- if (ioctl(ioctlfd, SIOCAIFADDR, &ifaliasreq) == -1)
- log_warn("%s: SIOCAIFADDR %s", log_procname,
- inet_ntoa(addr));
-}
-
-void
-delete_address(char *name, int ioctlfd, struct in_addr addr)
-{
- struct ifaliasreq ifaliasreq;
- struct sockaddr_in *in;
-
- /*
- * Delete specified address on specified interface.
- *
- * Deleting the address also clears out arp entries.
- */
-
- memset(&ifaliasreq, 0, sizeof(ifaliasreq));
- strncpy(ifaliasreq.ifra_name, name, sizeof(ifaliasreq.ifra_name));
-
- in = (struct sockaddr_in *)&ifaliasreq.ifra_addr;
- in->sin_family = AF_INET;
- in->sin_len = sizeof(ifaliasreq.ifra_addr);
- in->sin_addr.s_addr = addr.s_addr;
-
- /* SIOCDIFADDR will result in a RTM_DELADDR message we must catch! */
- if (ioctl(ioctlfd, SIOCDIFADDR, &ifaliasreq) == -1) {
- if (errno != EADDRNOTAVAIL)
- log_warn("%s: SIOCDIFADDR %s", log_procname,
- inet_ntoa(addr));
- }
-}
-
-/*
- * get_routes() returns all relevant routes currently configured, and the
- * length of the buffer being returned.
- */
-char *
-get_routes(int rdomain, size_t *len)
-{
- int mib[7];
- char *buf, *bufp, *errmsg = NULL;
- size_t needed;
-
- mib[0] = CTL_NET;
- mib[1] = PF_ROUTE; /* PF_ROUTE (not AF_ROUTE) for sysctl(2)! */
- mib[2] = 0;
- mib[3] = AF_INET;
- mib[4] = NET_RT_FLAGS;
- mib[5] = RTF_STATIC;
- mib[6] = rdomain;
-
- buf = NULL;
- errmsg = NULL;
- for (;;) {
- if (sysctl(mib, 7, NULL, &needed, NULL, 0) == -1) {
- errmsg = "sysctl size of routes:";
- break;
- }
- if (needed == 0) {
- free(buf);
- return NULL;
- }
- if ((bufp = realloc(buf, needed)) == NULL) {
- errmsg = "routes buf realloc:";
- break;
- }
- buf = bufp;
- if (sysctl(mib, 7, buf, &needed, NULL, 0) == -1) {
- if (errno == ENOMEM)
- continue;
- errmsg = "sysctl retrieval of routes:";
- break;
- }
- break;
- }
-
- if (errmsg != NULL) {
- log_warn("%s: get_routes - %s (msize=%zu)", log_procname,
- errmsg, needed);
- free(buf);
- buf = NULL;
- }
-
- *len = needed;
- return buf;
-}
-
-/*
- * get_rtaddrs() populates rti_info with pointers to the
- * sockaddr's contained in a rtm message.
- */
-void
-get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info)
-{
- int i;
-
- for (i = 0; i < RTAX_MAX; i++) {
- if (addrs & (1 << i)) {
- rti_info[i] = sa;
- sa = (struct sockaddr *)((char *)(sa) +
- ROUNDUP(sa->sa_len));
- } else
- rti_info[i] = NULL;
- }
-}
-/*
- * route_pos() finds the position of the *rtm route within
- * routes.
- *
- * If the *rtm route is not in routes, return routes_len.
- */
-unsigned int
-route_pos(struct rt_msghdr *rtm, uint8_t *routes, unsigned int routes_len,
- struct in_addr address)
-{
- struct sockaddr *rti_info[RTAX_MAX];
- struct sockaddr *dst, *netmask, *gateway;
- in_addr_t dstaddr, netmaskaddr, gatewayaddr;
- in_addr_t routesdstaddr, routesnetmaskaddr;
- in_addr_t routesgatewayaddr;
- unsigned int i, len;
-
- get_rtaddrs(rtm->rtm_addrs,
- (struct sockaddr *)((char *)(rtm) + rtm->rtm_hdrlen),
- rti_info);
-
- dst = rti_info[RTAX_DST];
- netmask = rti_info[RTAX_NETMASK];
- gateway = rti_info[RTAX_GATEWAY];
-
- if (dst == NULL || netmask == NULL || gateway == NULL)
- return routes_len;
-
- if (dst->sa_family != AF_INET || netmask->sa_family != AF_INET ||
- gateway->sa_family != AF_INET)
- return routes_len;
-
- dstaddr = ((struct sockaddr_in *)dst)->sin_addr.s_addr;
- netmaskaddr = ((struct sockaddr_in *)netmask)->sin_addr.s_addr;
- gatewayaddr = ((struct sockaddr_in *)gateway)->sin_addr.s_addr;
-
- dstaddr &= netmaskaddr;
- i = 0;
- while (i < routes_len) {
- len = extract_route(&routes[i], routes_len - i, &routesdstaddr,
- &routesnetmaskaddr, &routesgatewayaddr);
- if (len == 0)
- break;
-
- /* Direct route in routes:
- *
- * dst=1.2.3.4 netmask=255.255.255.255 gateway=0.0.0.0
- *
- * direct route in rtm:
- *
- * dst=1.2.3.4 netmask=255.255.255.255 gateway = address
- *
- * So replace 0.0.0.0 with address for comparison.
- */
- if (routesgatewayaddr == INADDR_ANY)
- routesgatewayaddr = address.s_addr;
- routesdstaddr &= routesnetmaskaddr;
-
- if (dstaddr == routesdstaddr &&
- netmaskaddr == routesnetmaskaddr &&
- gatewayaddr == routesgatewayaddr)
- return i;
-
- i += len;
- }
-
- return routes_len;
-}
-
-void
-flush_routes(int index, int routefd, int rdomain, uint8_t *routes,
- unsigned int routes_len, struct in_addr address)
-{
- static int seqno;
- char *lim, *buf, *next;
- struct rt_msghdr *rtm;
- size_t len;
- ssize_t rlen;
- unsigned int pos;
-
- buf = get_routes(rdomain, &len);
- if (buf == NULL)
- return;
-
- lim = buf + len;
- for (next = buf; next < lim; next += rtm->rtm_msglen) {
- rtm = (struct rt_msghdr *)next;
- if (rtm->rtm_version != RTM_VERSION)
- continue;
- if (rtm->rtm_index != index)
- continue;
- if (rtm->rtm_tableid != rdomain)
- continue;
- if ((rtm->rtm_flags & RTF_STATIC) == 0)
- continue;
- if ((rtm->rtm_flags & (RTF_LOCAL|RTF_BROADCAST)) != 0)
- continue;
-
- pos = route_pos(rtm, routes, routes_len, address);
- if (pos < routes_len) {
- discard_route(routes + pos, routes_len - pos);
- continue;
- }
-
- rtm->rtm_type = RTM_DELETE;
- rtm->rtm_seq = seqno++;
-
- rlen = write(routefd, (char *)rtm, rtm->rtm_msglen);
- if (rlen == -1) {
- if (errno != ESRCH)
- log_warn("%s: write(RTM_DELETE)", log_procname);
- } else if (rlen < (int)rtm->rtm_msglen)
- log_warnx("%s: write(RTM_DELETE): %zd of %u bytes",
- log_procname, rlen, rtm->rtm_msglen);
- }
-
- free(buf);
-}
-
-void
-discard_route(uint8_t *routes, unsigned int routes_len)
-{
- unsigned int len;
-
- len = 1 + sizeof(struct in_addr) + (routes[0] + 7) / 8;
- memmove(routes, routes + len, routes_len - len);
- routes[routes_len - len] = CIDR_MAX_BITS + 1;
-}
-
-/*
- * add_route() adds a single route to the routing table.
- */
-void
-add_route(char *name, int rdomain, int routefd, struct in_addr dest,
- struct in_addr netmask, struct in_addr gateway, struct in_addr address,
- int flags)
-{
- char destbuf[INET_ADDRSTRLEN];
- char maskbuf[INET_ADDRSTRLEN];
- struct iovec iov[5];
- struct sockaddr_in sockaddr_in[4];
- struct rt_msghdr rtm;
- int i, iovcnt = 0;
-
- memset(&rtm, 0, sizeof(rtm));
- rtm.rtm_index = if_nametoindex(name);
- if (rtm.rtm_index == 0)
- return;
-
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_type = RTM_ADD;
- rtm.rtm_tableid = rdomain;
- rtm.rtm_priority = RTP_NONE;
- rtm.rtm_flags = flags;
-
- iov[0].iov_base = &rtm;
- iov[0].iov_len = sizeof(rtm);
-
- memset(sockaddr_in, 0, sizeof(sockaddr_in));
- for (i = 0; i < 4; i++) {
- sockaddr_in[i].sin_len = sizeof(sockaddr_in[i]);
- sockaddr_in[i].sin_family = AF_INET;
- iov[i+1].iov_base = &sockaddr_in[i];
- iov[i+1].iov_len = sizeof(sockaddr_in[i]);
- }
-
- /* Order of sockaddr_in's is mandatory! */
- sockaddr_in[0].sin_addr = dest;
- sockaddr_in[1].sin_addr = gateway;
- sockaddr_in[2].sin_addr = netmask;
- sockaddr_in[3].sin_addr = address;
- if (address.s_addr == INADDR_ANY) {
- rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK;
- iovcnt = 4;
- } else {
- rtm.rtm_addrs = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_IFA;
- iovcnt = 5;
- }
-
- for (i = 0; i < iovcnt; i++)
- rtm.rtm_msglen += iov[i].iov_len;
-
- if (writev(routefd, iov, iovcnt) == -1) {
- if (errno != EEXIST || log_getverbose() != 0) {
- strlcpy(destbuf, inet_ntoa(dest), sizeof(destbuf));
- strlcpy(maskbuf, inet_ntoa(netmask),sizeof(maskbuf));
- log_warn("%s: add route %s/%s via %s", log_procname,
- destbuf, maskbuf, inet_ntoa(gateway));
- }
- }
-}
-
-/*
- * set_routes() adds the routes contained in 'routes' to the routing table.
- */
-void
-set_routes(char *name, int index, int rdomain, int routefd, struct in_addr addr,
- struct in_addr addrmask, uint8_t *routes, unsigned int routes_len)
-{
- const struct in_addr any = { INADDR_ANY };
- const struct in_addr broadcast = { INADDR_BROADCAST };
- struct in_addr dest, gateway, netmask;
- in_addr_t addrnet, gatewaynet;
- unsigned int i, len;
-
- flush_routes(index, routefd, rdomain, routes, routes_len, addr);
-
- addrnet = addr.s_addr & addrmask.s_addr;
-
- /* Add classless static routes. */
- i = 0;
- while (i < routes_len) {
- len = extract_route(&routes[i], routes_len - i,
- &dest.s_addr, &netmask.s_addr, &gateway.s_addr);
- if (len == 0)
- return;
- i += len;
-
- if (gateway.s_addr == INADDR_ANY) {
- /*
- * DIRECT ROUTE
- *
- * route add -net $dest -netmask $netmask -cloning
- * -iface $addr
- */
- add_route(name, rdomain, routefd, dest, netmask,
- addr, any, RTF_STATIC | RTF_CLONING);
- } else if (netmask.s_addr == INADDR_ANY) {
- /*
- * DEFAULT ROUTE
- */
- gatewaynet = gateway.s_addr & addrmask.s_addr;
- if (gatewaynet != addrnet) {
- /*
- * DIRECT ROUTE TO DEFAULT GATEWAY
- *
- * route add -net $gateway
- * -netmask 255.255.255.255
- * -cloning -iface $addr
- *
- * If the default route gateway is not reachable
- * via the IP assignment then add a cloning
- * direct route for the gateway. Deals with
- * weird configs seen in the wild.
- *
- * e.g. add the route if we were given a /32 IP
- * assignment. a.k.a. "make Google Cloud DHCP
- * work".
- *
- */
- add_route(name, rdomain, routefd, gateway,
- broadcast, addr, any,
- RTF_STATIC | RTF_CLONING);
- }
-
- if (memcmp(&gateway, &addr, sizeof(addr)) == 0) {
- /*
- * DEFAULT ROUTE IS A DIRECT ROUTE
- *
- * route add default -iface $addr
- */
- add_route(name, rdomain, routefd, any, any,
- gateway, any, RTF_STATIC);
- } else {
- /*
- * DEFAULT ROUTE IS VIA GATEWAY
- *
- * route add default $gateway -ifa $addr
- *
- */
- add_route(name, rdomain, routefd, any, any,
- gateway, addr, RTF_STATIC | RTF_GATEWAY);
- }
- } else {
- /*
- * NON-DIRECT, NON-DEFAULT ROUTE
- *
- * route add -net $dest -netmask $netmask $gateway
- */
- add_route(name, rdomain, routefd, dest, netmask,
- gateway, any, RTF_STATIC | RTF_GATEWAY);
- }
- }
-}
-
-/*
- * default_route_index() returns the interface index of the current
- * default route (a.k.a. 0.0.0.0/0).
- */
-int
-default_route_index(int rdomain, int routefd)
-{
- struct pollfd fds[1];
- struct timespec now, stop, timeout;
- int nfds;
- struct iovec iov[3];
- struct sockaddr_in sin;
- struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
- } m_rtmsg;
- pid_t pid;
- ssize_t len;
- int seq;
-
- memset(&m_rtmsg, 0, sizeof(m_rtmsg));
- m_rtmsg.m_rtm.rtm_version = RTM_VERSION;
- m_rtmsg.m_rtm.rtm_type = RTM_GET;
- m_rtmsg.m_rtm.rtm_tableid = rdomain;
- m_rtmsg.m_rtm.rtm_seq = seq = arc4random();
- m_rtmsg.m_rtm.rtm_addrs = RTA_DST | RTA_NETMASK;
- m_rtmsg.m_rtm.rtm_msglen = sizeof(struct rt_msghdr) +
- 2 * sizeof(struct sockaddr_in);
-
- memset(&sin, 0, sizeof(sin));
- sin.sin_len = sizeof(sin);
- sin.sin_family = AF_INET;
-
- iov[0].iov_base = &m_rtmsg.m_rtm;
- iov[0].iov_len = sizeof(m_rtmsg.m_rtm);
- iov[1].iov_base = &sin;
- iov[1].iov_len = sizeof(sin);
- iov[2].iov_base = &sin;
- iov[2].iov_len = sizeof(sin);
-
- pid = getpid();
- clock_gettime(CLOCK_MONOTONIC, &now);
- timespecclear(&timeout);
- timeout.tv_sec = 3;
- timespecadd(&now, &timeout, &stop);
-
- if (writev(routefd, iov, 3) == -1) {
- if (errno == ESRCH)
- log_debug("%s: writev(RTM_GET) - no default route",
- log_procname);
- else
- log_warn("%s: writev(RTM_GET)", log_procname);
- return 0;
- }
-
- for (;;) {
- clock_gettime(CLOCK_MONOTONIC, &now);
- if (timespeccmp(&stop, &now, <=))
- break;
- timespecsub(&stop, &now, &timeout);
-
- fds[0].fd = routefd;
- fds[0].events = POLLIN;
- nfds = ppoll(fds, 1, &timeout, NULL);
- if (nfds == -1) {
- if (errno == EINTR)
- continue;
- log_warn("%s: ppoll(routefd)", log_procname);
- break;
- }
- if ((fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) != 0) {
- log_warnx("%s: routefd: ERR|HUP|NVAL", log_procname);
- break;
- }
- if (nfds == 0 || (fds[0].revents & POLLIN) == 0)
- continue;
-
- len = read(routefd, &m_rtmsg, sizeof(m_rtmsg));
- if (len == -1) {
- log_warn("%s: read(RTM_GET)", log_procname);
- break;
- } else if (len == 0) {
- log_warnx("%s: read(RTM_GET): 0 bytes", log_procname);
- break;
- }
-
- if (m_rtmsg.m_rtm.rtm_version == RTM_VERSION &&
- m_rtmsg.m_rtm.rtm_type == RTM_GET &&
- m_rtmsg.m_rtm.rtm_pid == pid &&
- m_rtmsg.m_rtm.rtm_seq == seq &&
- (m_rtmsg.m_rtm.rtm_flags & RTF_UP) == RTF_UP) {
- if (m_rtmsg.m_rtm.rtm_errno != 0) {
- log_warnx("%s: read(RTM_GET): %s", log_procname,
- strerror(m_rtmsg.m_rtm.rtm_errno));
- break;
- }
- return m_rtmsg.m_rtm.rtm_index;
- }
- }
-
- return 0;
-}
-
-/*
- * resolv_conf_tail() returns the contents of /etc/resolv.conf.tail, if
- * any. NULL is returned if there is no such file, the file is emtpy
- * or any errors are encounted in reading the file.
- */
-char *
-resolv_conf_tail(void)
-{
- struct stat sb;
- const char *tail_path = "/etc/resolv.conf.tail";
- char *tailcontents = NULL;
- ssize_t tailn;
- int tailfd;
-
- tailfd = open(tail_path, O_RDONLY);
- if (tailfd == -1) {
- if (errno != ENOENT)
- log_warn("%s: open(%s)", log_procname, tail_path);
- } else if (fstat(tailfd, &sb) == -1) {
- log_warn("%s: fstat(%s)", log_procname, tail_path);
- } else if (sb.st_size > 0 && sb.st_size < LLONG_MAX) {
- tailcontents = calloc(1, sb.st_size + 1);
- if (tailcontents == NULL)
- fatal("%s contents", tail_path);
- tailn = read(tailfd, tailcontents, sb.st_size);
- if (tailn == -1)
- log_warn("%s: read(%s)", log_procname,
- tail_path);
- else if (tailn == 0)
- log_warnx("%s: got no data from %s",
- log_procname,tail_path);
- else if (tailn != sb.st_size)
- log_warnx("%s: short read of %s",
- log_procname, tail_path);
- else {
- close(tailfd);
- return tailcontents;
- }
-
- close(tailfd);
- free(tailcontents);
- }
-
- return NULL;
-}
-
-/*
- * set_resolv_conf() creates a string that are the resolv.conf contents
- * that should be used when IMSG_WRITE_RESOLV_CONF messages are received.
- */
-char *
-set_resolv_conf(char *name, char *search, struct unwind_info *ns_info)
-{
- char *ns, *p, *tail;
- struct in_addr addr;
- unsigned int i;
- int rslt;
-
- ns = NULL;
- for (i = 0; i < ns_info->count; i++) {
- addr.s_addr = ns_info->ns[i];
- rslt = asprintf(&p, "%snameserver %s\n",
- (ns == NULL) ? "" : ns, inet_ntoa(addr));
- if (rslt == -1)
- fatal("nameserver");
- free(ns);
- ns = p;
- }
-
- if (search == NULL && ns == NULL)
- return NULL;
-
- tail = resolv_conf_tail();
-
- rslt = asprintf(&p, "# Generated by %s dhclient\n%s%s%s", name,
- (search == NULL) ? "" : search,
- (ns == NULL) ? "" : ns,
- (tail == NULL) ? "" : tail);
- if (rslt == -1)
- fatal("resolv.conf");
-
- free(tail);
- free(ns);
-
- return p;
-}
-
-/*
- * set_mtu() is the equivalent of
- *
- * ifconfig <if> mtu <mtu>
- */
-void
-set_mtu(char *name, int ioctlfd, uint16_t mtu)
-{
- struct ifreq ifr;
-
- memset(&ifr, 0, sizeof(ifr));
- strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
-
- if (ioctl(ioctlfd, SIOCGIFMTU, &ifr) == -1) {
- log_warn("%s: SIOCGIFMTU", log_procname);
- return;
- }
- if (ifr.ifr_mtu == mtu)
- return; /* Avoid unnecessary RTM_IFINFO! */
-
- ifr.ifr_mtu = mtu;
- if (ioctl(ioctlfd, SIOCSIFMTU, &ifr) == -1)
- log_warn("%s: SIOCSIFMTU %u", log_procname, mtu);
-}
-
-/*
- * extract_route() decodes the route pointed to by routes into its
- * {destination, netmask, gateway} and returns the number of bytes consumed
- * from routes.
- */
-unsigned int
-extract_route(uint8_t *routes, unsigned int routes_len, in_addr_t *dest,
- in_addr_t *netmask, in_addr_t *gateway)
-{
- unsigned int bits, bytes, len;
-
- if (routes[0] > CIDR_MAX_BITS)
- return 0;
-
- bits = routes[0];
- bytes = (bits + 7) / 8;
- len = 1 + bytes + sizeof(*gateway);
- if (len > routes_len)
- return 0;
-
- if (dest != NULL)
- memcpy(dest, &routes[1], bytes);
-
- if (netmask != NULL) {
- if (bits == 0)
- *netmask = INADDR_ANY;
- else
- *netmask = htonl(0xffffffff << (CIDR_MAX_BITS - bits));
- if (dest != NULL)
- *dest &= *netmask;
- }
-
- if (gateway != NULL)
- memcpy(gateway, &routes[1 + bytes], sizeof(*gateway));
-
- return len;
-}
-
-/*
- * [priv_]write_resolv_conf write out a new resolv.conf.
- */
-void
-write_resolv_conf(void)
-{
- int rslt;
-
- rslt = imsg_compose(unpriv_ibuf, IMSG_WRITE_RESOLV_CONF,
- 0, 0, -1, NULL, 0);
- if (rslt == -1)
- log_warn("%s: imsg_compose(IMSG_WRITE_RESOLV_CONF)",
- log_procname);
-}
-
-void
-priv_write_resolv_conf(int index, int routefd, int rdomain, char *contents,
- int *lastidx)
-{
- char ifname[IF_NAMESIZE];
- const char *path = "/etc/resolv.conf";
- ssize_t n;
- size_t sz;
- int fd, retries, newidx;
-
- if (contents == NULL)
- return;
-
- retries = 0;
- do {
- newidx = default_route_index(rdomain, routefd);
- retries++;
- } while (newidx == 0 && retries < 3);
-
- if (newidx == 0) {
- log_debug("%s: %s not updated, no default route is UP",
- log_procname, path);
- return;
- } else if (newidx != index) {
- *lastidx = newidx;
- if (if_indextoname(newidx, ifname) == NULL) {
- memset(ifname, 0, sizeof(ifname));
- strlcat(ifname, "<unknown>", sizeof(ifname));
- }
- log_debug("%s: %s not updated, default route on %s",
- log_procname, path, ifname);
- return;
- } else if (newidx == *lastidx) {
- log_debug("%s: %s not updated, same as last write",
- log_procname, path);
- return;
- }
-
- *lastidx = newidx;
- log_debug("%s: %s updated", log_procname, path);
-
- fd = open(path, O_WRONLY | O_CREAT | O_TRUNC,
- S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
- if (fd == -1) {
- log_warn("%s: open(%s)", log_procname, path);
- return;
- }
-
- sz = strlen(contents);
- n = write(fd, contents, sz);
- if (n == -1)
- log_warn("%s: write(%s)", log_procname, path);
- else if ((size_t)n < sz)
- log_warnx("%s: write(%s): %zd of %zu bytes", log_procname,
- path, n, sz);
-
- close(fd);
-}
-
-/*
- * [priv_]propose implements a proposal.
- */
-void
-propose(struct proposal *proposal)
-{
- struct option_data opt;
- int rslt;
-
- log_debug("%s: proposing address %s netmask 0x%08x", log_procname,
- inet_ntoa(proposal->address), ntohl(proposal->netmask.s_addr));
-
- opt.data = (u_int8_t *)proposal + sizeof(struct proposal);
- opt.len = proposal->routes_len;
- if (opt.len > 0)
- log_debug("%s: proposing static route(s) %s", log_procname,
- pretty_print_option(DHO_CLASSLESS_STATIC_ROUTES, &opt, 0));
-
- opt.data += opt.len;
- opt.len = proposal->domains_len;
- if (opt.len > 0)
- log_debug("%s: proposing search domain(s) %s", log_procname,
- pretty_print_option(DHO_DOMAIN_SEARCH, &opt, 0));
-
- opt.data += opt.len;
- opt.len = proposal->ns_len;
- if (opt.len > 0)
- log_debug("%s: proposing DNS server(s) %s", log_procname,
- pretty_print_option(DHO_DOMAIN_NAME_SERVERS, &opt, 0));
-
- if (proposal->mtu != 0)
- log_debug("%s: proposing mtu %u", log_procname, proposal->mtu);
-
- rslt = imsg_compose(unpriv_ibuf, IMSG_PROPOSE, 0, 0, -1, proposal,
- sizeof(*proposal) + proposal->routes_len +
- proposal->domains_len + proposal->ns_len);
- if (rslt == -1)
- log_warn("%s: imsg_compose(IMSG_PROPOSE)", log_procname);
-}
-
-void
-priv_propose(char *name, int ioctlfd, struct proposal *proposal,
- size_t sz, char **resolv_conf, int routefd, int rdomain, int index,
- int *lastidx)
-{
- struct unwind_info unwind_info;
- uint8_t *dns, *domains, *routes;
- char *search = NULL;
- int rslt;
-
- if (sz != proposal->routes_len + proposal->domains_len +
- proposal->ns_len) {
- log_warnx("%s: bad IMSG_PROPOSE data", log_procname);
- return;
- }
-
- routes = (uint8_t *)proposal + sizeof(struct proposal);
- domains = routes + proposal->routes_len;
- dns = domains + proposal->domains_len;
-
- memset(&unwind_info, 0, sizeof(unwind_info));
- if (proposal->ns_len >= sizeof(in_addr_t)) {
- if (proposal->ns_len > sizeof(unwind_info.ns)) {
- memcpy(unwind_info.ns, dns, sizeof(unwind_info.ns));
- unwind_info.count = sizeof(unwind_info.ns) /
- sizeof(in_addr_t);
- } else {
- memcpy(unwind_info.ns, dns, proposal->ns_len);
- unwind_info.count = proposal->ns_len /
- sizeof(in_addr_t);
- }
- }
-
- if (proposal->domains_len > 0) {
- rslt = asprintf(&search, "search %.*s\n",
- proposal->domains_len, domains);
- if (rslt == -1)
- search = NULL;
- }
-
- free(*resolv_conf);
- *resolv_conf = set_resolv_conf(name, search, &unwind_info);
- free(search);
-
- if (proposal->mtu != 0) {
- if (proposal->mtu < 68)
- log_warnx("%s: mtu size %d < 68: ignored", log_procname,
- proposal->mtu);
- else
- set_mtu(name, ioctlfd, proposal->mtu);
- }
-
- set_address(name, ioctlfd, proposal->address, proposal->netmask);
-
- set_routes(name, index, rdomain, routefd, proposal->address,
- proposal->netmask, routes, proposal->routes_len);
-
- *lastidx = 0;
- priv_write_resolv_conf(index, routefd, rdomain, *resolv_conf, lastidx);
-}
-
-/*
- * [priv_]revoke_proposal de-configures a proposal.
- */
-void
-revoke_proposal(struct proposal *proposal)
-{
- int rslt;
-
- if (proposal == NULL)
- return;
-
- rslt = imsg_compose(unpriv_ibuf, IMSG_REVOKE, 0, 0, -1, proposal,
- sizeof(*proposal));
- if (rslt == -1)
- log_warn("%s: imsg_compose(IMSG_REVOKE)", log_procname);
-}
-
-void
-priv_revoke_proposal(char *name, int ioctlfd, struct proposal *proposal,
- char **resolv_conf)
-{
- free(*resolv_conf);
- *resolv_conf = NULL;
-
- delete_address(name, ioctlfd, proposal->address);
-}
-
-/*
- * [priv_]tell_unwind sends out inforation unwind may be intereted in.
- */
-void
-tell_unwind(struct unwind_info *unwind_info, int ifi_flags)
-{
- struct unwind_info noinfo;
- int rslt;
-
- if ((ifi_flags & IFI_IN_CHARGE) == 0)
- return;
-
- if (unwind_info != NULL)
- rslt = imsg_compose(unpriv_ibuf, IMSG_TELL_UNWIND, 0, 0, -1,
- unwind_info, sizeof(*unwind_info));
- else {
- memset(&noinfo, 0, sizeof(noinfo));
- rslt = imsg_compose(unpriv_ibuf, IMSG_TELL_UNWIND, 0, 0, -1,
- &noinfo, sizeof(noinfo));
- }
-
- if (rslt == -1)
- log_warn("%s: imsg_compose(IMSG_TELL_UNWIND)", log_procname);
-}
-
-void
-priv_tell_unwind(int index, int routefd, int rdomain,
- struct unwind_info *unwind_info)
-{
- struct rt_msghdr rtm;
- struct sockaddr_rtdns rtdns;
- struct iovec iov[3];
- long pad = 0;
- int iovcnt = 0, padlen;
-
- memset(&rtm, 0, sizeof(rtm));
-
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_type = RTM_PROPOSAL;
- rtm.rtm_msglen = sizeof(rtm);
- rtm.rtm_tableid = rdomain;
- rtm.rtm_index = index;
- rtm.rtm_seq = arc4random();
- rtm.rtm_priority = RTP_PROPOSAL_DHCLIENT;
- rtm.rtm_addrs = RTA_DNS;
- rtm.rtm_flags = RTF_UP;
-
- iov[iovcnt].iov_base = &rtm;
- iov[iovcnt++].iov_len = sizeof(rtm);
-
- memset(&rtdns, 0, sizeof(rtdns));
- rtdns.sr_family = AF_INET;
-
- rtdns.sr_len = 2 + unwind_info->count * sizeof(in_addr_t);
- memcpy(rtdns.sr_dns, unwind_info->ns,
- unwind_info->count * sizeof(in_addr_t));
-
- iov[iovcnt].iov_base = &rtdns;
- iov[iovcnt++].iov_len = sizeof(rtdns);
- rtm.rtm_msglen += sizeof(rtdns);
- padlen = ROUNDUP(sizeof(rtdns)) - sizeof(rtdns);
- if (padlen > 0) {
- iov[iovcnt].iov_base = &pad;
- iov[iovcnt++].iov_len = padlen;
- rtm.rtm_msglen += padlen;
- }
-
- if (writev(routefd, iov, iovcnt) == -1)
- log_warn("failed to tell unwind");
-}
+++ /dev/null
-/* $OpenBSD: log.c,v 1.2 2017/03/21 12:06:55 bluhm Exp $ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <syslog.h>
-#include <errno.h>
-#include <time.h>
-
-#include "log.h"
-
-static int debug;
-static int verbose;
-static const char *log_procname;
-
-void
-log_init(int n_debug, int facility)
-{
- extern char *__progname;
-
- debug = n_debug;
- verbose = n_debug;
- log_procinit(__progname);
-
- if (!debug)
- openlog(__progname, LOG_PID | LOG_NDELAY, facility);
-
- tzset();
-}
-
-void
-log_procinit(const char *procname)
-{
- if (procname != NULL)
- log_procname = procname;
-}
-
-void
-log_setverbose(int v)
-{
- verbose = v;
-}
-
-int
-log_getverbose(void)
-{
- return (verbose);
-}
-
-void
-logit(int pri, const char *fmt, ...)
-{
- va_list ap;
-
- va_start(ap, fmt);
- vlog(pri, fmt, ap);
- va_end(ap);
-}
-
-void
-vlog(int pri, const char *fmt, va_list ap)
-{
- char *nfmt;
- int saved_errno = errno;
-
- if (debug) {
- /* best effort in out of mem situations */
- if (asprintf(&nfmt, "%s\n", fmt) == -1) {
- vfprintf(stderr, fmt, ap);
- fprintf(stderr, "\n");
- } else {
- vfprintf(stderr, nfmt, ap);
- free(nfmt);
- }
- fflush(stderr);
- } else
- vsyslog(pri, fmt, ap);
-
- errno = saved_errno;
-}
-
-void
-log_warn(const char *emsg, ...)
-{
- char *nfmt;
- va_list ap;
- int saved_errno = errno;
-
- /* best effort to even work in out of memory situations */
- if (emsg == NULL)
- logit(LOG_ERR, "%s", strerror(saved_errno));
- else {
- va_start(ap, emsg);
-
- if (asprintf(&nfmt, "%s: %s", emsg,
- strerror(saved_errno)) == -1) {
- /* we tried it... */
- vlog(LOG_ERR, emsg, ap);
- logit(LOG_ERR, "%s", strerror(saved_errno));
- } else {
- vlog(LOG_ERR, nfmt, ap);
- free(nfmt);
- }
- va_end(ap);
- }
-
- errno = saved_errno;
-}
-
-void
-log_warnx(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_ERR, emsg, ap);
- va_end(ap);
-}
-
-void
-log_info(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vlog(LOG_INFO, emsg, ap);
- va_end(ap);
-}
-
-void
-log_debug(const char *emsg, ...)
-{
- va_list ap;
-
- if (verbose) {
- va_start(ap, emsg);
- vlog(LOG_DEBUG, emsg, ap);
- va_end(ap);
- }
-}
-
-static void
-vfatalc(int code, const char *emsg, va_list ap)
-{
- static char s[BUFSIZ];
- const char *sep;
-
- if (emsg != NULL) {
- (void)vsnprintf(s, sizeof(s), emsg, ap);
- sep = ": ";
- } else {
- s[0] = '\0';
- sep = "";
- }
- if (code)
- logit(LOG_CRIT, "fatal in %s: %s%s%s",
- log_procname, s, sep, strerror(code));
- else
- logit(LOG_CRIT, "fatal in %s%s%s", log_procname, sep, s);
-}
-
-void
-fatal(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vfatalc(errno, emsg, ap);
- va_end(ap);
- exit(1);
-}
-
-void
-fatalx(const char *emsg, ...)
-{
- va_list ap;
-
- va_start(ap, emsg);
- vfatalc(0, emsg, ap);
- va_end(ap);
- exit(1);
-}
+++ /dev/null
-/* $OpenBSD: log.h,v 1.2 2021/12/13 18:28:39 deraadt Exp $ */
-
-/*
- * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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.
- */
-
-#ifndef LOG_H
-#define LOG_H
-
-#include <stdarg.h>
-
-void log_init(int, int);
-void log_procinit(const char *);
-void log_setverbose(int);
-int log_getverbose(void);
-void log_warn(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_warnx(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_info(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void log_debug(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-void logit(int, const char *, ...)
- __attribute__((__format__ (printf, 2, 3)));
-void vlog(int, const char *, va_list)
- __attribute__((__format__ (printf, 2, 0)));
-__dead void fatal(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-__dead void fatalx(const char *, ...)
- __attribute__((__format__ (printf, 1, 2)));
-
-#endif /* LOG_H */
+++ /dev/null
-/* $OpenBSD: options.c,v 1.123 2020/07/07 19:48:31 krw Exp $ */
-
-/* DHCP options parsing and reassembly. */
-
-/*
- * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <arpa/inet.h>
-
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <ctype.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <vis.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-
-int parse_option_buffer(struct option_data *, unsigned char *, int);
-void pretty_print_classless_routes(unsigned char *, size_t, unsigned char *,
- size_t);
-void pretty_print_domain_list(unsigned char *, size_t, unsigned char *,
- size_t);
-
-/*
- * DHCP Option names, formats and codes, from RFC1533.
- *
- * Format codes:
- *
- * e - end of data
- * I - IP address
- * l - 32-bit signed integer
- * L - 32-bit unsigned integer
- * S - 16-bit unsigned integer
- * B - 8-bit unsigned integer
- * t - ASCII text
- * f - flag (true or false)
- * A - array of whatever precedes (e.g., IA means array of IP addresses)
- * C - CIDR description
- * X - hex octets
- * D - domain name list, comma separated list of domain names.
- */
-
-static const struct {
- char *name;
- char *format;
-} dhcp_options[DHO_COUNT] = {
- /* 0 */ { "pad", "" },
- /* 1 */ { "subnet-mask", "I" },
- /* 2 */ { "time-offset", "l" },
- /* 3 */ { "routers", "IA" },
- /* 4 */ { "time-servers", "IA" },
- /* 5 */ { "ien116-name-servers", "IA" },
- /* 6 */ { "domain-name-servers", "IA" },
- /* 7 */ { "log-servers", "IA" },
- /* 8 */ { "cookie-servers", "IA" },
- /* 9 */ { "lpr-servers", "IA" },
- /* 10 */ { "impress-servers", "IA" },
- /* 11 */ { "resource-location-servers", "IA" },
- /* 12 */ { "host-name", "t" },
- /* 13 */ { "boot-size", "S" },
- /* 14 */ { "merit-dump", "t" },
- /* 15 */ { "domain-name", "t" },
- /* 16 */ { "swap-server", "I" },
- /* 17 */ { "root-path", "t" },
- /* 18 */ { "extensions-path", "t" },
- /* 19 */ { "ip-forwarding", "f" },
- /* 20 */ { "non-local-source-routing", "f" },
- /* 21 */ { "policy-filter", "IIA" },
- /* 22 */ { "max-dgram-reassembly", "S" },
- /* 23 */ { "default-ip-ttl", "B" },
- /* 24 */ { "path-mtu-aging-timeout", "L" },
- /* 25 */ { "path-mtu-plateau-table", "SA" },
- /* 26 */ { "interface-mtu", "S" },
- /* 27 */ { "all-subnets-local", "f" },
- /* 28 */ { "broadcast-address", "I" },
- /* 29 */ { "perform-mask-discovery", "f" },
- /* 30 */ { "mask-supplier", "f" },
- /* 31 */ { "router-discovery", "f" },
- /* 32 */ { "router-solicitation-address", "I" },
- /* 33 */ { "static-routes", "IIA" },
- /* 34 */ { "trailer-encapsulation", "f" },
- /* 35 */ { "arp-cache-timeout", "L" },
- /* 36 */ { "ieee802-3-encapsulation", "f" },
- /* 37 */ { "default-tcp-ttl", "B" },
- /* 38 */ { "tcp-keepalive-interval", "L" },
- /* 39 */ { "tcp-keepalive-garbage", "f" },
- /* 40 */ { "nis-domain", "t" },
- /* 41 */ { "nis-servers", "IA" },
- /* 42 */ { "ntp-servers", "IA" },
- /* 43 */ { "vendor-encapsulated-options", "X" },
- /* 44 */ { "netbios-name-servers", "IA" },
- /* 45 */ { "netbios-dd-server", "IA" },
- /* 46 */ { "netbios-node-type", "B" },
- /* 47 */ { "netbios-scope", "t" },
- /* 48 */ { "font-servers", "IA" },
- /* 49 */ { "x-display-manager", "IA" },
- /* 50 */ { "dhcp-requested-address", "I" },
- /* 51 */ { "dhcp-lease-time", "L" },
- /* 52 */ { "dhcp-option-overload", "B" },
- /* 53 */ { "dhcp-message-type", "B" },
- /* 54 */ { "dhcp-server-identifier", "I" },
- /* 55 */ { "dhcp-parameter-request-list", "BA" },
- /* 56 */ { "dhcp-message", "t" },
- /* 57 */ { "dhcp-max-message-size", "S" },
- /* 58 */ { "dhcp-renewal-time", "L" },
- /* 59 */ { "dhcp-rebinding-time", "L" },
- /* 60 */ { "dhcp-class-identifier", "t" },
- /* 61 */ { "dhcp-client-identifier", "X" },
- /* 62 */ { NULL, NULL },
- /* 63 */ { NULL, NULL },
- /* 64 */ { "nisplus-domain", "t" },
- /* 65 */ { "nisplus-servers", "IA" },
- /* 66 */ { "tftp-server-name", "t" },
- /* 67 */ { "bootfile-name", "t" },
- /* 68 */ { "mobile-ip-home-agent", "IA" },
- /* 69 */ { "smtp-server", "IA" },
- /* 70 */ { "pop-server", "IA" },
- /* 71 */ { "nntp-server", "IA" },
- /* 72 */ { "www-server", "IA" },
- /* 73 */ { "finger-server", "IA" },
- /* 74 */ { "irc-server", "IA" },
- /* 75 */ { "streettalk-server", "IA" },
- /* 76 */ { "streettalk-directory-assistance-server", "IA" },
- /* 77 */ { "user-class", "t" },
- /* 78 */ { NULL, NULL },
- /* 79 */ { NULL, NULL },
- /* 80 */ { NULL, NULL },
- /* 81 */ { NULL, NULL },
- /* 82 */ { "relay-agent-information", "X" },
- /* 83 */ { NULL, NULL },
- /* 84 */ { NULL, NULL },
- /* 85 */ { "nds-servers", "IA" },
- /* 86 */ { "nds-tree-name", "X" },
- /* 87 */ { "nds-context", "X" },
- /* 88 */ { NULL, NULL },
- /* 89 */ { NULL, NULL },
- /* 90 */ { NULL, NULL },
- /* 91 */ { NULL, NULL },
- /* 92 */ { NULL, NULL },
- /* 93 */ { NULL, NULL },
- /* 94 */ { NULL, NULL },
- /* 95 */ { NULL, NULL },
- /* 96 */ { NULL, NULL },
- /* 97 */ { NULL, NULL },
- /* 98 */ { NULL, NULL },
- /* 99 */ { NULL, NULL },
- /* 100 */ { NULL, NULL },
- /* 101 */ { NULL, NULL },
- /* 102 */ { NULL, NULL },
- /* 103 */ { NULL, NULL },
- /* 104 */ { NULL, NULL },
- /* 105 */ { NULL, NULL },
- /* 106 */ { NULL, NULL },
- /* 107 */ { NULL, NULL },
- /* 108 */ { NULL, NULL },
- /* 109 */ { NULL, NULL },
- /* 110 */ { NULL, NULL },
- /* 111 */ { NULL, NULL },
- /* 112 */ { NULL, NULL },
- /* 113 */ { NULL, NULL },
- /* 114 */ { NULL, NULL },
- /* 115 */ { NULL, NULL },
- /* 116 */ { NULL, NULL },
- /* 117 */ { NULL, NULL },
- /* 118 */ { NULL, NULL },
- /* 119 */ { "domain-search", "D" },
- /* 120 */ { NULL, NULL },
- /* 121 */ { "classless-static-routes", "CIA" },
- /* 122 */ { NULL, NULL },
- /* 123 */ { NULL, NULL },
- /* 124 */ { NULL, NULL },
- /* 125 */ { NULL, NULL },
- /* 126 */ { NULL, NULL },
- /* 127 */ { NULL, NULL },
- /* 128 */ { NULL, NULL },
- /* 129 */ { NULL, NULL },
- /* 130 */ { NULL, NULL },
- /* 131 */ { NULL, NULL },
- /* 132 */ { NULL, NULL },
- /* 133 */ { NULL, NULL },
- /* 134 */ { NULL, NULL },
- /* 135 */ { NULL, NULL },
- /* 136 */ { NULL, NULL },
- /* 137 */ { NULL, NULL },
- /* 138 */ { NULL, NULL },
- /* 139 */ { NULL, NULL },
- /* 140 */ { NULL, NULL },
- /* 141 */ { NULL, NULL },
- /* 142 */ { NULL, NULL },
- /* 143 */ { NULL, NULL },
- /* 144 */ { "tftp-config-file", "t" },
- /* 145 */ { NULL, NULL },
- /* 146 */ { NULL, NULL },
- /* 147 */ { NULL, NULL },
- /* 148 */ { NULL, NULL },
- /* 149 */ { NULL, NULL },
- /* 150 */ { "voip-configuration-server", "IA" },
- /* 151 */ { NULL, NULL },
- /* 152 */ { NULL, NULL },
- /* 153 */ { NULL, NULL },
- /* 154 */ { NULL, NULL },
- /* 155 */ { NULL, NULL },
- /* 156 */ { NULL, NULL },
- /* 157 */ { NULL, NULL },
- /* 158 */ { NULL, NULL },
- /* 159 */ { NULL, NULL },
- /* 160 */ { NULL, NULL },
- /* 161 */ { NULL, NULL },
- /* 162 */ { NULL, NULL },
- /* 163 */ { NULL, NULL },
- /* 164 */ { NULL, NULL },
- /* 165 */ { NULL, NULL },
- /* 166 */ { NULL, NULL },
- /* 167 */ { NULL, NULL },
- /* 168 */ { NULL, NULL },
- /* 169 */ { NULL, NULL },
- /* 170 */ { NULL, NULL },
- /* 171 */ { NULL, NULL },
- /* 172 */ { NULL, NULL },
- /* 173 */ { NULL, NULL },
- /* 174 */ { NULL, NULL },
- /* 175 */ { NULL, NULL },
- /* 176 */ { NULL, NULL },
- /* 177 */ { NULL, NULL },
- /* 178 */ { NULL, NULL },
- /* 179 */ { NULL, NULL },
- /* 180 */ { NULL, NULL },
- /* 181 */ { NULL, NULL },
- /* 182 */ { NULL, NULL },
- /* 183 */ { NULL, NULL },
- /* 184 */ { NULL, NULL },
- /* 185 */ { NULL, NULL },
- /* 186 */ { NULL, NULL },
- /* 187 */ { NULL, NULL },
- /* 188 */ { NULL, NULL },
- /* 189 */ { NULL, NULL },
- /* 190 */ { NULL, NULL },
- /* 191 */ { NULL, NULL },
- /* 192 */ { NULL, NULL },
- /* 193 */ { NULL, NULL },
- /* 194 */ { NULL, NULL },
- /* 195 */ { NULL, NULL },
- /* 196 */ { NULL, NULL },
- /* 197 */ { NULL, NULL },
- /* 198 */ { NULL, NULL },
- /* 199 */ { NULL, NULL },
- /* 200 */ { NULL, NULL },
- /* 201 */ { NULL, NULL },
- /* 202 */ { NULL, NULL },
- /* 203 */ { NULL, NULL },
- /* 204 */ { NULL, NULL },
- /* 205 */ { NULL, NULL },
- /* 206 */ { NULL, NULL },
- /* 207 */ { NULL, NULL },
- /* 208 */ { NULL, NULL },
- /* 209 */ { NULL, NULL },
- /* 210 */ { NULL, NULL },
- /* 211 */ { NULL, NULL },
- /* 212 */ { NULL, NULL },
- /* 213 */ { NULL, NULL },
- /* 214 */ { NULL, NULL },
- /* 215 */ { NULL, NULL },
- /* 216 */ { NULL, NULL },
- /* 217 */ { NULL, NULL },
- /* 218 */ { NULL, NULL },
- /* 219 */ { NULL, NULL },
- /* 220 */ { NULL, NULL },
- /* 221 */ { NULL, NULL },
- /* 222 */ { NULL, NULL },
- /* 223 */ { NULL, NULL },
- /* 224 */ { NULL, NULL },
- /* 225 */ { NULL, NULL },
- /* 226 */ { NULL, NULL },
- /* 227 */ { NULL, NULL },
- /* 228 */ { NULL, NULL },
- /* 229 */ { NULL, NULL },
- /* 230 */ { NULL, NULL },
- /* 231 */ { NULL, NULL },
- /* 232 */ { NULL, NULL },
- /* 233 */ { NULL, NULL },
- /* 234 */ { NULL, NULL },
- /* 235 */ { NULL, NULL },
- /* 236 */ { NULL, NULL },
- /* 237 */ { NULL, NULL },
- /* 238 */ { NULL, NULL },
- /* 239 */ { NULL, NULL },
- /* 240 */ { NULL, NULL },
- /* 241 */ { NULL, NULL },
- /* 242 */ { NULL, NULL },
- /* 243 */ { NULL, NULL },
- /* 244 */ { NULL, NULL },
- /* 245 */ { NULL, NULL },
- /* 246 */ { NULL, NULL },
- /* 247 */ { NULL, NULL },
- /* 248 */ { NULL, NULL },
- /* 249 */ { "classless-ms-static-routes", "CIA" },
- /* 250 */ { NULL, NULL },
- /* 251 */ { NULL, NULL },
- /* 252 */ { "autoproxy-script", "t" },
- /* 253 */ { NULL, NULL },
- /* 254 */ { NULL, NULL },
- /* 255 */ { "option-end", "e" },
-};
-
-char *
-code_to_name(int code)
-{
- static char unknown[11]; /* "option-NNN" */
- int ret;
-
- if (code < 0 || code >= DHO_COUNT)
- return "";
-
- if (dhcp_options[code].name != NULL)
- return dhcp_options[code].name;
-
- ret = snprintf(unknown, sizeof(unknown), "option-%d", code);
- if (ret < 0 || ret >= (int)sizeof(unknown))
- return "";
-
- return unknown;
-}
-
-int
-name_to_code(char *name)
-{
- char unknown[11]; /* "option-NNN" */
- int code, ret;
-
- for (code = 1; code < DHO_END; code++) {
- if (dhcp_options[code].name == NULL) {
- ret = snprintf(unknown, sizeof(unknown), "option-%d",
- code);
- if (ret < 0 || ret >= (int)sizeof(unknown))
- return DHO_END;
- if (strcasecmp(unknown, name) == 0)
- return code;
- } else if (strcasecmp(dhcp_options[code].name, name) == 0) {
- return code;
- }
- }
-
- return DHO_END;
-}
-
-char *
-code_to_format(int code)
-{
- if (code < 0 || code >= DHO_COUNT)
- return "";
-
- if (dhcp_options[code].format == NULL)
- return "X";
-
- return dhcp_options[code].format;
-}
-
-/*
- * Some option data types cannot be appended or prepended to. For
- * such options change ACTION_PREPEND to ACTION_SUPERSEDE and
- * ACTION_APPEND to ACTION_DEFAULT.
- */
-int
-code_to_action(int code, int action)
-{
- char *fmt;
-
- fmt = code_to_format(code);
- if (fmt == NULL || strpbrk(fmt, "ADtX") != NULL)
- return action;
-
- /*
- * For our protection all formats which have been excluded shall be
- * deemed included.
- */
- switch (action) {
- case ACTION_APPEND:
- action = ACTION_DEFAULT;
- break;
- case ACTION_PREPEND:
- action = ACTION_SUPERSEDE;
- break;
- default:
- break;
- }
-
- return action;
-}
-
-/*
- * Parse options out of the specified buffer, storing addresses of
- * option values in options. Return 0 if errors, 1 if not.
- */
-int
-parse_option_buffer(struct option_data *options, unsigned char *buffer,
- int length)
-{
- unsigned char *s, *t, *end;
- char *name, *fmt;
- int code, len, newlen;
-
- s = buffer;
- end = s + length;
- while (s < end) {
- code = s[0];
-
- /* End options terminate processing. */
- if (code == DHO_END)
- break;
-
- /* Pad options don't have a length - just skip them. */
- if (code == DHO_PAD) {
- s++;
- continue;
- }
-
- name = code_to_name(code);
- fmt = code_to_format(code);
-
- /*
- * All options other than DHO_PAD and DHO_END have a one-byte
- * length field. It could be 0! Make sure that the length byte
- * is present, and all the data is available.
- */
- if (s + 1 < end) {
- len = s[1];
- if (s + 1 + len < end) {
- ; /* option data is all there. */
- } else {
- log_warnx("%s: option %s (%d) larger than "
- "buffer", log_procname, name, len);
- return 0;
- }
- } else {
- log_warnx("%s: option %s has no length field",
- log_procname, name);
- return 0;
- }
-
- /*
- * Strip trailing NULs from ascii ('t') options. RFC 2132
- * says "Options containing NVT ASCII data SHOULD NOT include
- * a trailing NULL; however, the receiver of such options
- * MUST be prepared to delete trailing nulls if they exist."
- */
- if (fmt[0] == 't') {
- while (len > 0 && s[len + 1] == '\0')
- len--;
- }
-
- /*
- * Concatenate new data + NUL to existing option data.
- *
- * Note that the NUL is *not* counted in the len field!
- */
- newlen = options[code].len + len;
- if ((t = realloc(options[code].data, newlen + 1)) == NULL)
- fatal("option %s", name);
-
- memcpy(t + options[code].len, &s[2], len);
- t[newlen] = 0;
-
- options[code].len = newlen;
- options[code].data = t;
-
- s += s[1] + 2;
- }
-
- return 1;
-}
-
-/*
- * Pack as many options as fit in buflen bytes of buf. Return the
- * offset of the start of the last option copied. A caller can check
- * to see if it's DHO_END to decide if all the options were copied.
- */
-int
-pack_options(unsigned char *buf, int buflen, struct option_data *options)
-{
- int ix, incr, length, bufix, code, lastopt = -1;
-
- memset(buf, 0, buflen);
-
- memcpy(buf, DHCP_OPTIONS_COOKIE, 4);
- if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL) {
- memcpy(&buf[4], DHCP_OPTIONS_MESSAGE_TYPE, 3);
- buf[6] = options[DHO_DHCP_MESSAGE_TYPE].data[0];
- bufix = 7;
- } else
- bufix = 4;
-
- for (code = DHO_SUBNET_MASK; code < DHO_END; code++) {
- if (options[code].data == NULL ||
- code == DHO_DHCP_MESSAGE_TYPE)
- continue;
-
- length = options[code].len;
- if (bufix + length + 2*((length+254)/255) >= buflen)
- return lastopt;
-
- lastopt = bufix;
- ix = 0;
-
- while (length) {
- incr = length > 255 ? 255 : length;
-
- buf[bufix++] = code;
- buf[bufix++] = incr;
- memcpy(buf + bufix, options[code].data + ix, incr);
-
- length -= incr;
- ix += incr;
- bufix += incr;
- }
- }
-
- if (bufix < buflen) {
- buf[bufix] = DHO_END;
- lastopt = bufix;
- }
-
- return lastopt;
-}
-
-/*
- * Use vis() to encode characters of src and append encoded characters onto
- * dst. Also encode ", ', $, ` and \, to ensure resulting strings can be
- * represented as '"' delimited strings and safely passed to scripts. Surround
- * result with double quotes if emit_punct is true.
- */
-char *
-pretty_print_string(unsigned char *src, size_t srclen, int emit_punct)
-{
- static char string[8196];
- char visbuf[5];
- unsigned char *origsrc = src;
- size_t rslt = 0;
-
- memset(string, 0, sizeof(string));
-
- if (emit_punct != 0)
- rslt = strlcat(string, "\"", sizeof(string));
-
- for (; src < origsrc + srclen; src++) {
- if (*src && strchr("\"'$`\\", *src))
- vis(visbuf, *src, VIS_ALL | VIS_OCTAL, *src+1);
- else
- vis(visbuf, *src, VIS_OCTAL, *src+1);
- rslt = strlcat(string, visbuf, sizeof(string));
- }
-
- if (emit_punct != 0)
- rslt = strlcat(string, "\"", sizeof(string));
-
- if (rslt >= sizeof(string))
- return NULL;
-
- return string;
-}
-
-/*
- * Must special case *_CLASSLESS_* route options due to the variable size
- * of the CIDR element in its CIA format.
- */
-void
-pretty_print_classless_routes(unsigned char *src, size_t srclen,
- unsigned char *buf, size_t buflen)
-{
- char bitsbuf[5]; /* to hold "/nn " */
- struct in_addr dest, netmask, gateway;
- unsigned int bits, i, len;
- uint32_t m;
- int rslt;
-
- i = 0;
- while (i < srclen) {
- len = extract_route(&src[i], srclen - i, &dest.s_addr,
- &netmask.s_addr, &gateway.s_addr);
- if (len == 0)
- goto bad;
- i += len;
-
- m = ntohl(netmask.s_addr);
- bits = 32;
- while ((bits > 0) && ((m & 1) == 0)) {
- m >>= 1;
- bits--;
- }
-
- rslt = snprintf(bitsbuf, sizeof(bitsbuf), "/%d ", bits);
- if (rslt < 0 || (unsigned int)rslt >= sizeof(bitsbuf))
- goto bad;
-
- if (strlen(buf) > 0)
- strlcat(buf, ", ", buflen);
- strlcat(buf, inet_ntoa(dest), buflen);
- strlcat(buf, bitsbuf, buflen);
- if (strlcat(buf, inet_ntoa(gateway), buflen) >= buflen)
- goto bad;
- }
-
- return;
-
-bad:
- memset(buf, 0, buflen);
-}
-
-/*
- * Print string containing blank separated list of domain names
- * as a comma separated list of double-quote delimited strings.
- *
- * e.g. "eng.apple.com. marketing.apple.com."
- *
- * will be translated to
- *
- * "eng.apple.com.", "marketing.apple.com."
- */
-void
-pretty_print_domain_list(unsigned char *src, size_t srclen,
- unsigned char *buf, size_t buflen)
-{
- char *dupnames, *hn, *inputstring;
- int count;
-
- memset(buf, 0, buflen);
-
- /*
- * N.B.: option data is *NOT* guaranteed to be NUL
- * terminated. Avoid strlen(), strdup(), etc.!
- */
- if (srclen >= DHCP_DOMAIN_SEARCH_LEN || src[0] == '\0')
- return;
-
- inputstring = malloc(srclen + 1);
- if (inputstring == NULL)
- fatal("domain name list");
- memcpy(inputstring, src, srclen);
- inputstring[srclen] = '\0';
- dupnames = inputstring;
-
- count = 0;
- while ((hn = strsep(&inputstring, " \t")) != NULL) {
- if (strlen(hn) == 0)
- continue;
- if (res_hnok(hn) == 0)
- goto bad;
- if (count > 0)
- strlcat(buf, ", ", buflen);
- strlcat(buf, "\"", buflen);
- strlcat(buf, hn, buflen);
- if (strlcat(buf, "\"", buflen) >= buflen)
- goto bad;
- count++;
- if (count > DHCP_DOMAIN_SEARCH_CNT)
- goto bad;
- }
-
- free(dupnames);
- return;
-
-bad:
- free(dupnames);
- memset(buf, 0, buflen);
-}
-
-/*
- * Format the specified option so that a human can easily read it.
- */
-char *
-pretty_print_option(unsigned int code, struct option_data *option,
- int emit_punct)
-{
- static char optbuf[8192]; /* XXX */
- char fmtbuf[32];
- struct in_addr foo;
- unsigned char *data = option->data;
- unsigned char *dp = data;
- char *op = optbuf, *buf, *name, *fmt;
- int hunksize = 0, numhunk = -1, numelem = 0;
- int i, j, k, opleft = sizeof(optbuf);
- int len = option->len;
- int opcount = 0;
- int32_t int32val;
- uint32_t uint32val;
- uint16_t uint16val;
- char comma;
-
- memset(optbuf, 0, sizeof(optbuf));
-
- /* Code should be between 0 and 255. */
- if (code > 255) {
- log_warnx("%s: pretty_print_option: bad code %d", log_procname,
- code);
- goto done;
- }
-
- if (emit_punct != 0)
- comma = ',';
- else
- comma = ' ';
-
- /* Handle the princess class options with weirdo formats. */
- switch (code) {
- case DHO_CLASSLESS_STATIC_ROUTES:
- case DHO_CLASSLESS_MS_STATIC_ROUTES:
- pretty_print_classless_routes(dp, len, optbuf, sizeof(optbuf));
- goto done;
- case DHO_DOMAIN_SEARCH:
- pretty_print_domain_list(dp, len, optbuf, sizeof(optbuf));
- goto done;
- default:
- break;
- }
-
- name = code_to_name(code);
- fmt = code_to_format(code);
-
- /* Figure out the size of the data. */
- for (i = 0; fmt[i]; i++) {
- if (numhunk == 0) {
- log_warnx("%s: %s: excess information in format "
- "string: %s", log_procname, name, &fmt[i]);
- goto done;
- }
- numelem++;
- fmtbuf[i] = fmt[i];
- switch (fmt[i]) {
- case 'A':
- --numelem;
- fmtbuf[i] = 0;
- numhunk = 0;
- if (hunksize == 0) {
- log_warnx("%s: %s: no size indicator before A"
- " in format string: %s", log_procname,
- name, fmt);
- goto done;
- }
- break;
- case 'X':
- for (k = 0; k < len; k++)
- if (isascii(data[k]) == 0 ||
- isprint(data[k]) == 0)
- break;
- if (k == len) {
- fmtbuf[i] = 't';
- numhunk = -2;
- } else {
- hunksize++;
- comma = ':';
- numhunk = 0;
- }
- fmtbuf[i + 1] = 0;
- break;
- case 't':
- fmtbuf[i + 1] = 0;
- numhunk = -2;
- break;
- case 'I':
- case 'l':
- case 'L':
- hunksize += 4;
- break;
- case 'S':
- hunksize += 2;
- break;
- case 'B':
- case 'f':
- hunksize++;
- break;
- case 'e':
- break;
- default:
- log_warnx("%s: %s: garbage in format string: %s",
- log_procname, name, &fmt[i]);
- goto done;
- }
- }
-
- /* Check for too few bytes. */
- if (hunksize > len) {
- log_warnx("%s: %s: expecting at least %d bytes; got %d",
- log_procname, name, hunksize, len);
- goto done;
- }
- /* Check for too many bytes. */
- if (numhunk == -1 && hunksize < len) {
- log_warnx("%s: %s: expecting only %d bytes: got %d",
- log_procname, name, hunksize, len);
- goto done;
- }
-
- /* If this is an array, compute its size. */
- if (numhunk == 0)
- numhunk = len / hunksize;
- /* See if we got an exact number of hunks. */
- if (numhunk > 0 && numhunk * hunksize != len) {
- log_warnx("%s: %s: expecting %d bytes: got %d", log_procname,
- name, numhunk * hunksize, len);
- goto done;
- }
-
- /* A one-hunk array prints the same as a single hunk. */
- if (numhunk < 0)
- numhunk = 1;
-
- /* Cycle through the array (or hunk) printing the data. */
- for (i = 0; i < numhunk; i++) {
- for (j = 0; j < numelem; j++) {
- switch (fmtbuf[j]) {
- case 't':
- buf = pretty_print_string(dp, len, emit_punct);
- if (buf == NULL)
- opcount = -1;
- else
- opcount = strlcat(op, buf, opleft);
- break;
- case 'I':
- memcpy(&foo.s_addr, dp, sizeof(foo.s_addr));
- opcount = snprintf(op, opleft, "%s",
- inet_ntoa(foo));
- dp += sizeof(foo.s_addr);
- break;
- case 'l':
- memcpy(&int32val, dp, sizeof(int32val));
- opcount = snprintf(op, opleft, "%d",
- ntohl(int32val));
- dp += sizeof(int32val);
- break;
- case 'L':
- memcpy(&uint32val, dp, sizeof(uint32val));
- opcount = snprintf(op, opleft, "%u",
- ntohl(uint32val));
- dp += sizeof(uint32val);
- break;
- case 'S':
- memcpy(&uint16val, dp, sizeof(uint16val));
- opcount = snprintf(op, opleft, "%hu",
- ntohs(uint16val));
- dp += sizeof(uint16val);
- break;
- case 'B':
- opcount = snprintf(op, opleft, "%u", *dp);
- dp++;
- break;
- case 'X':
- opcount = snprintf(op, opleft, "%x", *dp);
- dp++;
- break;
- case 'f':
- opcount = snprintf(op, opleft, "%s",
- *dp ? "true" : "false");
- dp++;
- break;
- default:
- log_warnx("%s: unexpected format code %c",
- log_procname, fmtbuf[j]);
- goto toobig;
- }
- if (opcount < 0 || opcount >= opleft)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- if (j + 1 < numelem && comma != ':') {
- opcount = snprintf(op, opleft, " ");
- if (opcount < 0 || opcount >= opleft)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- }
- }
- if (i + 1 < numhunk) {
- opcount = snprintf(op, opleft, "%c", comma);
- if (opcount < 0 || opcount >= opleft)
- goto toobig;
- opleft -= opcount;
- op += opcount;
- }
- }
-
-done:
- return optbuf;
-
-toobig:
- memset(optbuf, 0, sizeof(optbuf));
- return optbuf;
-}
-
-struct option_data *
-unpack_options(struct dhcp_packet *packet)
-{
- static struct option_data options[DHO_COUNT];
- int i;
-
- for (i = 0; i < DHO_COUNT; i++) {
- free(options[i].data);
- options[i].data = NULL;
- options[i].len = 0;
- }
-
- if (memcmp(&packet->options, DHCP_OPTIONS_COOKIE, 4) == 0) {
- /* Parse the BOOTP/DHCP options field. */
- parse_option_buffer(options, &packet->options[4],
- sizeof(packet->options) - 4);
-
- /* DHCP packets can also use overload areas for options. */
- if (options[DHO_DHCP_MESSAGE_TYPE].data != NULL &&
- options[DHO_DHCP_OPTION_OVERLOAD].data != NULL) {
- if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 1) !=
- 0)
- parse_option_buffer(options,
- (unsigned char *)packet->file,
- sizeof(packet->file));
- if ((options[DHO_DHCP_OPTION_OVERLOAD].data[0] & 2) !=
- 0)
- parse_option_buffer(options,
- (unsigned char *)packet->sname,
- sizeof(packet->sname));
- }
- }
-
- return options;
-}
-
-void
-merge_option_data(char *fmt, struct option_data *first,
- struct option_data *second, struct option_data *dest)
-{
- int space = 0;
-
- free(dest->data);
- dest->data = NULL;
- dest->len = first->len + second->len;
- if (dest->len == 0)
- return;
-
- /*
- * N.B.: option data is *NOT* guaranteed to be NUL
- * terminated. Avoid strlen(), strdup(), etc.!
- */
- if (fmt[0] == 'D') {
- if (first->len > 0 && second->len > 0)
- space = 1;
- }
-
- dest->len += space;
- dest->data = malloc(dest->len);
- if (dest->data == NULL)
- fatal("merged option data");
-
- memcpy(dest->data, first->data, first->len);
- if (space == 1)
- dest->data[first->len] = ' ';
- memcpy(dest->data + first->len + space, second->data, second->len);
-}
+++ /dev/null
-/* $OpenBSD: packet.c,v 1.45 2021/02/22 23:43:59 jsg Exp $ */
-
-/* Packet assembly code, originally contributed by Archie Cobbs. */
-
-/*
- * Copyright (c) 1995, 1996, 1999 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/ip.h>
-#include <netinet/udp.h>
-#include <netinet/if_ether.h>
-
-#include <signal.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-
-uint32_t
-checksum(unsigned char *buf, uint32_t nbytes, uint32_t sum)
-{
- unsigned int i;
-
- /* Checksum all the pairs of bytes first. */
- for (i = 0; i < (nbytes & ~1U); i += 2) {
- sum += (uint16_t)ntohs(*((uint16_t *)(buf + i)));
- if (sum > 0xFFFF)
- sum -= 0xFFFF;
- }
-
- /*
- * If there's a single byte left over, checksum it, too.
- * Network byte order is big-endian, so the remaining byte is
- * the high byte.
- */
- if (i < nbytes) {
- sum += buf[i] << 8;
- if (sum > 0xFFFF)
- sum -= 0xFFFF;
- }
-
- return sum;
-}
-
-uint32_t
-wrapsum(uint32_t sum)
-{
- sum = ~sum & 0xFFFF;
- return htons(sum);
-}
-
-void
-assemble_eh_header(struct ether_addr shost, struct ether_header *eh)
-{
- memset(eh->ether_dhost, 0xff, sizeof(eh->ether_dhost));
-
- memcpy(eh->ether_shost, shost.ether_addr_octet,
- sizeof(eh->ether_shost));
-
- eh->ether_type = htons(ETHERTYPE_IP);
-}
-
-ssize_t
-decode_udp_ip_header(unsigned char *buf, uint32_t buflen,
- struct sockaddr_in *from)
-{
- static int ip_packets_seen;
- static int ip_packets_bad_checksum;
- static int udp_packets_seen;
- static int udp_packets_bad_checksum;
- static int udp_packets_length_checked;
- static int udp_packets_length_overflow;
- struct ip *ip;
- struct udphdr *udp;
- unsigned char *data;
- int len;
- uint32_t ip_len;
- uint32_t sum, usum;
-
- /* Assure that an entire IP header is within the buffer. */
- if (sizeof(*ip) > buflen)
- return -1;
- ip_len = (*buf & 0xf) << 2;
- if (ip_len > buflen)
- return -1;
- ip = (struct ip *)(buf);
- ip_packets_seen++;
-
- /* Check the IP header checksum - it should be zero. */
- if (wrapsum(checksum((unsigned char *)ip, ip_len, 0)) != 0) {
- ip_packets_bad_checksum++;
- if (ip_packets_seen > 4 && ip_packets_bad_checksum != 0 &&
- (ip_packets_seen / ip_packets_bad_checksum) < 2) {
- log_debug("%s: %d bad IP checksums seen in %d packets",
- log_procname, ip_packets_bad_checksum,
- ip_packets_seen);
- ip_packets_seen = ip_packets_bad_checksum = 0;
- }
- return -1;
- }
-
- memcpy(&from->sin_addr, &ip->ip_src, sizeof(from->sin_addr));
-
- if (ntohs(ip->ip_len) != buflen)
- log_debug("%s: ip length %hu disagrees with bytes received %d",
- log_procname, ntohs(ip->ip_len), buflen);
-
- /* Assure that the entire IP packet is within the buffer. */
- if (ntohs(ip->ip_len) > buflen)
- return -1;
-
- /* Assure that the UDP header is within the buffer. */
- if (ip_len + sizeof(*udp) > buflen)
- return -1;
- udp = (struct udphdr *)(buf + ip_len);
- udp_packets_seen++;
-
- /* Assure that the entire UDP packet is within the buffer. */
- if (ip_len + ntohs(udp->uh_ulen) > buflen)
- return -1;
- data = buf + ip_len + sizeof(*udp);
-
- /*
- * Compute UDP checksums, including the ``pseudo-header'', the
- * UDP header and the data. If the UDP checksum field is zero,
- * we're not supposed to do a checksum.
- */
- udp_packets_length_checked++;
- len = ntohs(udp->uh_ulen) - sizeof(*udp);
- if ((len < 0) || (len + data > buf + buflen)) {
- udp_packets_length_overflow++;
- if (udp_packets_length_checked > 4 &&
- udp_packets_length_overflow != 0 &&
- (udp_packets_length_checked /
- udp_packets_length_overflow) < 2) {
- log_debug("%s: %d udp packets in %d too long - dropped",
- log_procname, udp_packets_length_overflow,
- udp_packets_length_checked);
- udp_packets_length_overflow =
- udp_packets_length_checked = 0;
- }
- return -1;
- }
- if (len + data != buf + buflen)
- log_debug("%s: accepting packet with data after udp payload",
- log_procname);
-
- usum = udp->uh_sum;
- udp->uh_sum = 0;
-
- sum = wrapsum(checksum((unsigned char *)udp, sizeof(*udp),
- checksum(data, len, checksum((unsigned char *)&ip->ip_src,
- 2 * sizeof(ip->ip_src),
- IPPROTO_UDP + (uint32_t)ntohs(udp->uh_ulen)))));
-
- udp_packets_seen++;
- if (usum != 0 && usum != sum) {
- udp_packets_bad_checksum++;
- if (udp_packets_seen > 4 && udp_packets_bad_checksum != 0 &&
- (udp_packets_seen / udp_packets_bad_checksum) < 2) {
- log_debug("%s: %d bad udp checksums in %d packets",
- log_procname, udp_packets_bad_checksum,
- udp_packets_seen);
- udp_packets_seen = udp_packets_bad_checksum = 0;
- }
- return -1;
- }
-
- memcpy(&from->sin_port, &udp->uh_sport, sizeof(udp->uh_sport));
-
- return ip_len + sizeof(*udp);
-}
+++ /dev/null
-/* $OpenBSD: parse.c,v 1.83 2019/07/22 17:20:06 krw Exp $ */
-
-/* Common parser code for dhcpd and dhclient. */
-
-/*
- * Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of The Internet Software Consortium nor the names
- * of its contributors may be used to endorse or promote products derived
- * from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INTERNET SOFTWARE CONSORTIUM AND
- * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE INTERNET SOFTWARE CONSORTIUM OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This software has been written for the Internet Software Consortium
- * by Ted Lemon <mellon@fugue.com> in cooperation with Vixie
- * Enterprises. To learn more about the Internet Software Consortium,
- * see ``http://www.vix.com/isc''. To learn more about Vixie
- * Enterprises, see ``http://www.vix.com''.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <errno.h>
-#include <limits.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <syslog.h>
-#include <unistd.h>
-#include <vis.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "dhctoken.h"
-#include "log.h"
-
-/*
- * Skip to the semicolon ending the current statement. If we encounter
- * braces, the matching closing brace terminates the statement. If we
- * encounter a right brace but haven't encountered a left brace, return
- * leaving the brace in the token buffer for the caller. If we see a
- * semicolon and haven't seen a left brace, return. This lets us skip
- * over:
- *
- * statement;
- * statement foo bar { }
- * statement foo bar { statement { } }
- * statement}
- *
- * ...et cetera.
- */
-void
-skip_to_semi(FILE *cfile)
-{
- int token;
- int brace_count = 0;
-
- do {
- token = peek_token(NULL, cfile);
- if (token == '}') {
- if (brace_count > 0) {
- if (--brace_count == 0) {
- token = next_token(NULL, cfile);
- return;
- }
- } else
- return;
- } else if (token == '{') {
- brace_count++;
- } else if (token == ';' && brace_count == 0) {
- token = next_token(NULL, cfile);
- return;
- }
- token = next_token(NULL, cfile);
- } while (token != EOF);
-}
-
-int
-parse_semi(FILE *cfile)
-{
- int token;
-
- token = next_token(NULL, cfile);
- if (token == ';')
- return 1;
-
- parse_warn("expecting semicolon.");
- skip_to_semi(cfile);
-
- return 0;
-}
-
-int
-parse_string(FILE *cfile, char **string)
-{
- static char unvisbuf[1500];
- char *val;
- int i, token;
-
- token = next_token(&val, cfile);
- if (token == TOK_STRING) {
- i = strnunvis(unvisbuf, val, sizeof(unvisbuf));
- if (i >= 0) {
- *string = strdup(unvisbuf);
- if (*string == NULL)
- fatal("strdup(unvisbuf)");
- return 1;
- }
- }
-
- parse_warn("expecting string.");
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-/*
- * cidr :== ip-address "/" bit-count
- * ip-address :== NUMBER [ DOT NUMBER [ DOT NUMBER [ DOT NUMBER ] ] ]
- * bit-count :== 0..32
- */
-int
-parse_cidr(FILE *cfile, unsigned char *cidr)
-{
- uint8_t buf[5];
- const char *errstr;
- char *val;
- long long numval;
- unsigned int i;
- int token;
-
- memset(buf, 0, sizeof(buf));
- i = 1; /* Last four octets hold subnet, first octet the # of bits. */
- do {
- token = next_token(&val, cfile);
- if (i == 0)
- numval = strtonum(val, 0, 32, &errstr);
- else
- numval = strtonum(val, 0, UINT8_MAX, &errstr);
- if (errstr != NULL)
- break;
- buf[i++] = numval;
- if (i == 1) {
- memcpy(cidr, buf, sizeof(buf)); /* XXX Need cidr_t */
- return 1;
- }
- token = next_token(NULL, cfile);
- if (token == '/')
- i = 0;
- if (i == sizeof(buf))
- break;
- } while (token == '.' || token == '/');
-
- parse_warn("expecting IPv4 CIDR block.");
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-int
-parse_ip_addr(FILE *cfile, struct in_addr *addr)
-{
- struct in_addr buf;
- const char *errstr;
- char *val;
- long long numval;
- unsigned int i;
- int token;
-
- i = 0;
- do {
- token = next_token(&val, cfile);
- numval = strtonum(val, 0, UINT8_MAX, &errstr);
- if (errstr != NULL)
- break;
- ((uint8_t *)&buf)[i++] = numval;
- if (i == sizeof(buf)) {
- memcpy(addr, &buf, sizeof(*addr));
- return 1;
- }
- token = next_token(NULL, cfile);
- } while (token == '.');
-
- parse_warn("expecting IPv4 address.");
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-int
-parse_boolean(FILE *cfile, unsigned char *buf)
-{
- char *val;
- int token;
-
- token = next_token(&val, cfile);
- if (is_identifier(token) != 0) {
- if (strcasecmp(val, "true") == 0 ||
- strcasecmp(val, "on") == 0) {
- buf[0] = 1;
- return 1;
- }
- if (strcasecmp(val, "false") == 0 ||
- strcasecmp(val, "off") == 0) {
- buf[0] = 0;
- return 1;
- }
- }
-
- parse_warn("expecting boolean.");
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-int
-parse_number(FILE *cfile, long long *number, long long low, long long high)
-{
- const char *errstr;
- char *val, *msg;
- int rslt, token;
- long long numval;
-
- token = next_token(&val, cfile);
-
- numval = strtonum(val, low, high, &errstr);
- if (errstr == NULL) {
- *number = numval;
- return 1;
- }
-
- rslt = asprintf(&msg, "expecting integer between %lld and %lld", low,
- high);
- if (rslt != -1) {
- parse_warn(msg);
- free(msg);
- }
-
- if (token != ';')
- skip_to_semi(cfile);
-
- return 0;
-}
-
-void
-parse_warn(char *msg)
-{
- static char spaces[81];
- unsigned int i;
-
- log_warnx("%s: %s line %d: %s", log_procname, tlname, lexline, msg);
- log_warnx("%s: %s", log_procname, token_line);
- if ((unsigned int)lexchar < sizeof(spaces)) {
- memset(spaces, 0, sizeof(spaces));
- for (i = 0; (int)i < lexchar - 1; i++) {
- if (token_line[i] == '\t')
- spaces[i] = '\t';
- else
- spaces[i] = ' ';
- }
- log_warnx("%s: %s^", log_procname, spaces);
- }
-}
+++ /dev/null
-/* $OpenBSD: privsep.c,v 1.79 2020/11/21 18:34:25 krw Exp $ */
-
-/*
- * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/queue.h>
-#include <sys/socket.h>
-
-#include <net/if.h>
-#include <net/route.h>
-
-#include <netinet/in.h>
-#include <netinet/if_ether.h>
-
-#include <errno.h>
-#include <imsg.h>
-#include <resolv.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "dhcp.h"
-#include "dhcpd.h"
-#include "log.h"
-#include "privsep.h"
-
-void
-dispatch_imsg(char *name, int rdomain, int ioctlfd, int routefd,
- struct imsgbuf *ibuf)
-{
- static char *resolv_conf;
- static int lastidx;
- struct imsg imsg;
- ssize_t n;
- int index;
-
- index = if_nametoindex(name);
- if (index == 0) {
- log_warnx("%s: unknown interface", log_procname);
- quit = TERMINATE;
- return;
- }
-
- for (;;) {
- if ((n = imsg_get(ibuf, &imsg)) == -1)
- fatal("imsg_get");
-
- if (n == 0)
- break;
-
- switch (imsg.hdr.type) {
- case IMSG_REVOKE:
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct proposal))
- log_warnx("%s: bad IMSG_REVOKE",
- log_procname);
- else
- priv_revoke_proposal(name, ioctlfd, imsg.data,
- &resolv_conf);
- break;
-
- case IMSG_PROPOSE:
- if (imsg.hdr.len < IMSG_HEADER_SIZE +
- sizeof(struct proposal))
- log_warnx("%s: bad IMSG_PROPOSE",
- log_procname);
- else {
- priv_propose(name, ioctlfd, imsg.data,
- imsg.hdr.len - IMSG_HEADER_SIZE - sizeof(struct proposal),
- &resolv_conf, routefd, rdomain, index, &lastidx);
- }
- break;
-
- case IMSG_WRITE_RESOLV_CONF:
- if (imsg.hdr.len != IMSG_HEADER_SIZE)
- log_warnx("%s: bad IMSG_WRITE_RESOLV_CONF",
- log_procname);
- else
- priv_write_resolv_conf(index, routefd, rdomain,
- resolv_conf, &lastidx);
- break;
-
- case IMSG_TELL_UNWIND:
- if (imsg.hdr.len != IMSG_HEADER_SIZE +
- sizeof(struct unwind_info))
- log_warnx("%s: bad IMSG_TELL_UNWIND",
- log_procname);
- else
- priv_tell_unwind(index, routefd, rdomain, imsg.data);
- break;
-
- default:
- log_warnx("%s: received unknown message, code %u",
- log_procname, imsg.hdr.type);
- }
-
- imsg_free(&imsg);
- }
-}
+++ /dev/null
-/* $OpenBSD: privsep.h,v 1.70 2020/11/21 18:34:25 krw Exp $ */
-
-/*
- * Copyright (c) 2004 Henning Brauer <henning@openbsd.org>
- *
- * 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 MIND, USE, DATA OR PROFITS, WHETHER IN
- * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
- * OF OR IN CONNECTION WITH THE USE, ABUSE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-enum imsg_code {
- IMSG_NONE,
- IMSG_REVOKE,
- IMSG_WRITE_RESOLV_CONF,
- IMSG_PROPOSE,
- IMSG_TELL_UNWIND
-};
-
-struct proposal {
- struct in_addr address;
- struct in_addr netmask;
- unsigned int routes_len;
- unsigned int domains_len;
- unsigned int ns_len;
- int mtu;
-};
-
-struct unwind_info {
- in_addr_t ns[MAXNS];
- unsigned int count;
-};
-
-void dispatch_imsg(char *, int, int, int, struct imsgbuf *);
-
-void priv_write_resolv_conf(int, int, int, char *, int *);
-void priv_propose(char *, int, struct proposal *, size_t, char **, int, int,
- int, int *);
-
-void priv_revoke_proposal(char *, int, struct proposal *, char **);
-
-void priv_tell_unwind(int, int, int, struct unwind_info *);