diff options
author | Theo de Raadt <deraadt@cvs.openbsd.org> | 2024-06-30 17:30:55 +0000 |
---|---|---|
committer | Theo de Raadt <deraadt@cvs.openbsd.org> | 2024-06-30 17:30:55 +0000 |
commit | a1cc248fe949625cb503a288359f1fdc7f2805f7 (patch) | |
tree | 55111cc0774ffe5b351cecb1f6694f34c113bb2e | |
parent | 47f3f80cac9bf9d494ef6bf5e9e594eecac6541e (diff) |
delete dhclient(8). ipv4 dhcp leases have been acquired by the
always-running-in-background dhcpleased(8) for a while, which is
activated per-interface with "ifconfig $if autoconf', or
"ifconfig $if inet autoconf", or with "inet autoconf" in /etc/hostname.$if
dhclient(8) has done execve(3) of ifconfig(8) to handle this for a while,
so everyone has moved to the dhcpleased(8) method
ok florian
-rw-r--r-- | distrib/sets/lists/base/mi | 2 | ||||
-rw-r--r-- | distrib/sets/lists/man/mi | 3 | ||||
-rw-r--r-- | etc/Makefile | 4 | ||||
-rw-r--r-- | etc/examples/dhclient.conf | 15 | ||||
-rw-r--r-- | sbin/Makefile | 4 | ||||
-rw-r--r-- | sbin/dhclient/Makefile | 50 | ||||
-rw-r--r-- | sbin/dhclient/bpf.c | 401 | ||||
-rw-r--r-- | sbin/dhclient/clparse.c | 1029 | ||||
-rw-r--r-- | sbin/dhclient/conflex.c | 406 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.8 | 292 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.c | 2927 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.conf.5 | 301 | ||||
-rw-r--r-- | sbin/dhclient/dhclient.leases.5 | 170 | ||||
-rw-r--r-- | sbin/dhclient/dhcp.h | 201 | ||||
-rw-r--r-- | sbin/dhclient/dhcpd.h | 255 | ||||
-rw-r--r-- | sbin/dhclient/dhctoken.h | 82 | ||||
-rw-r--r-- | sbin/dhclient/dispatch.c | 322 | ||||
-rw-r--r-- | sbin/dhclient/kroute.c | 1072 | ||||
-rw-r--r-- | sbin/dhclient/log.c | 199 | ||||
-rw-r--r-- | sbin/dhclient/log.h | 45 | ||||
-rw-r--r-- | sbin/dhclient/options.c | 1001 | ||||
-rw-r--r-- | sbin/dhclient/packet.c | 215 | ||||
-rw-r--r-- | sbin/dhclient/parse.c | 300 | ||||
-rw-r--r-- | sbin/dhclient/privsep.c | 114 | ||||
-rw-r--r-- | sbin/dhclient/privsep.h | 49 |
25 files changed, 4 insertions, 9455 deletions
diff --git a/distrib/sets/lists/base/mi b/distrib/sets/lists/base/mi index 754cd4870d7..6132ea962b0 100644 --- a/distrib/sets/lists/base/mi +++ b/distrib/sets/lists/base/mi @@ -54,7 +54,6 @@ ./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 @@ -349,7 +348,6 @@ ./sbin/bioctl ./sbin/chown ./sbin/clri -./sbin/dhclient ./sbin/dhcp6leased ./sbin/dhcpleased ./sbin/disklabel diff --git a/distrib/sets/lists/man/mi b/distrib/sets/lists/man/mi index 5e32cc26489..6c769ec5953 100644 --- a/distrib/sets/lists/man/mi +++ b/distrib/sets/lists/man/mi @@ -2233,8 +2233,6 @@ ./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 @@ -2436,7 +2434,6 @@ ./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 diff --git a/etc/Makefile b/etc/Makefile index 5bac711ce30..2a80cccf2df 100644 --- a/etc/Makefile +++ b/etc/Makefile @@ -1,4 +1,4 @@ -# $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> @@ -45,7 +45,7 @@ MUTABLE=changelist daily etc.${MACHINE}/disktab \ 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 diff --git a/etc/examples/dhclient.conf b/etc/examples/dhclient.conf deleted file mode 100644 index 3fba6678cef..00000000000 --- a/etc/examples/dhclient.conf +++ /dev/null @@ -1,15 +0,0 @@ -# $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; diff --git a/sbin/Makefile b/sbin/Makefile index 81ac089fae6..19d0a8efa0d 100644 --- a/sbin/Makefile +++ b/sbin/Makefile @@ -1,6 +1,6 @@ -# $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 \ diff --git a/sbin/dhclient/Makefile b/sbin/dhclient/Makefile deleted file mode 100644 index b0113857654..00000000000 --- a/sbin/dhclient/Makefile +++ /dev/null @@ -1,50 +0,0 @@ -# $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> diff --git a/sbin/dhclient/bpf.c b/sbin/dhclient/bpf.c deleted file mode 100644 index 1bb287687fc..00000000000 --- a/sbin/dhclient/bpf.c +++ /dev/null @@ -1,401 +0,0 @@ -/* $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; -} diff --git a/sbin/dhclient/clparse.c b/sbin/dhclient/clparse.c deleted file mode 100644 index 051b3bb7a73..00000000000 --- a/sbin/dhclient/clparse.c +++ /dev/null @@ -1,1029 +0,0 @@ -/* $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); - } -} diff --git a/sbin/dhclient/conflex.c b/sbin/dhclient/conflex.c deleted file mode 100644 index cba4c6f09e7..00000000000 --- a/sbin/dhclient/conflex.c +++ /dev/null @@ -1,406 +0,0 @@ -/* $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; -} diff --git a/sbin/dhclient/dhclient.8 b/sbin/dhclient/dhclient.8 deleted file mode 100644 index 27895f91653..00000000000 --- a/sbin/dhclient/dhclient.8 +++ /dev/null @@ -1,292 +0,0 @@ -.\" $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 . diff --git a/sbin/dhclient/dhclient.c b/sbin/dhclient/dhclient.c deleted file mode 100644 index e96dae1f5d9..00000000000 --- a/sbin/dhclient/dhclient.c +++ /dev/null @@ -1,2927 +0,0 @@ -/* $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); - } -} diff --git a/sbin/dhclient/dhclient.conf.5 b/sbin/dhclient/dhclient.conf.5 deleted file mode 100644 index dcf110591b7..00000000000 --- a/sbin/dhclient/dhclient.conf.5 +++ /dev/null @@ -1,301 +0,0 @@ -.\" $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 diff --git a/sbin/dhclient/dhclient.leases.5 b/sbin/dhclient/dhclient.leases.5 deleted file mode 100644 index 782f71f3ad0..00000000000 --- a/sbin/dhclient/dhclient.leases.5 +++ /dev/null @@ -1,170 +0,0 @@ -.\" $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 diff --git a/sbin/dhclient/dhcp.h b/sbin/dhclient/dhcp.h deleted file mode 100644 index 644b9e4d789..00000000000 --- a/sbin/dhclient/dhcp.h +++ /dev/null @@ -1,201 +0,0 @@ -/* $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 diff --git a/sbin/dhclient/dhcpd.h b/sbin/dhclient/dhcpd.h deleted file mode 100644 index f0dd252fe45..00000000000 --- a/sbin/dhclient/dhcpd.h +++ /dev/null @@ -1,255 +0,0 @@ -/* $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); diff --git a/sbin/dhclient/dhctoken.h b/sbin/dhclient/dhctoken.h deleted file mode 100644 index c2d749c9826..00000000000 --- a/sbin/dhclient/dhctoken.h +++ /dev/null @@ -1,82 +0,0 @@ -/* $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) diff --git a/sbin/dhclient/dispatch.c b/sbin/dhclient/dispatch.c deleted file mode 100644 index 5951ba8efd3..00000000000 --- a/sbin/dhclient/dispatch.c +++ /dev/null @@ -1,322 +0,0 @@ -/* $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; -} diff --git a/sbin/dhclient/kroute.c b/sbin/dhclient/kroute.c deleted file mode 100644 index d85425f316f..00000000000 --- a/sbin/dhclient/kroute.c +++ /dev/null @@ -1,1072 +0,0 @@ -/* $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"); -} diff --git a/sbin/dhclient/log.c b/sbin/dhclient/log.c deleted file mode 100644 index 8956cd8279b..00000000000 --- a/sbin/dhclient/log.c +++ /dev/null @@ -1,199 +0,0 @@ -/* $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); -} diff --git a/sbin/dhclient/log.h b/sbin/dhclient/log.h deleted file mode 100644 index fc643129e8d..00000000000 --- a/sbin/dhclient/log.h +++ /dev/null @@ -1,45 +0,0 @@ -/* $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 */ diff --git a/sbin/dhclient/options.c b/sbin/dhclient/options.c deleted file mode 100644 index 84b76e1730c..00000000000 --- a/sbin/dhclient/options.c +++ /dev/null @@ -1,1001 +0,0 @@ -/* $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); -} diff --git a/sbin/dhclient/packet.c b/sbin/dhclient/packet.c deleted file mode 100644 index 8b4afbc7149..00000000000 --- a/sbin/dhclient/packet.c +++ /dev/null @@ -1,215 +0,0 @@ -/* $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); -} diff --git a/sbin/dhclient/parse.c b/sbin/dhclient/parse.c deleted file mode 100644 index fd0f7cbadc9..00000000000 --- a/sbin/dhclient/parse.c +++ /dev/null @@ -1,300 +0,0 @@ -/* $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); - } -} diff --git a/sbin/dhclient/privsep.c b/sbin/dhclient/privsep.c deleted file mode 100644 index dfddbe6ca26..00000000000 --- a/sbin/dhclient/privsep.c +++ /dev/null @@ -1,114 +0,0 @@ -/* $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); - } -} diff --git a/sbin/dhclient/privsep.h b/sbin/dhclient/privsep.h deleted file mode 100644 index 84a40a02d8f..00000000000 --- a/sbin/dhclient/privsep.h +++ /dev/null @@ -1,49 +0,0 @@ -/* $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 *); |