From owner-svn-soc-all@freebsd.org Mon Jun 29 01:32:00 2015 Return-Path: Delivered-To: svn-soc-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 7B4B398C504 for ; Mon, 29 Jun 2015 01:32:00 +0000 (UTC) (envelope-from sdouglas@FreeBSD.org) Received: from socsvn.freebsd.org (socsvn.freebsd.org [IPv6:2001:1900:2254:206a::50:2]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 6A90B15EC for ; Mon, 29 Jun 2015 01:32:00 +0000 (UTC) (envelope-from sdouglas@FreeBSD.org) Received: from socsvn.freebsd.org ([127.0.1.124]) by socsvn.freebsd.org (8.14.9/8.14.9) with ESMTP id t5T1W0hB043930 for ; Mon, 29 Jun 2015 01:32:00 GMT (envelope-from sdouglas@FreeBSD.org) Received: (from www@localhost) by socsvn.freebsd.org (8.14.9/8.14.9/Submit) id t5T1Vwlt043917 for svn-soc-all@FreeBSD.org; Mon, 29 Jun 2015 01:31:58 GMT (envelope-from sdouglas@FreeBSD.org) Date: Mon, 29 Jun 2015 01:31:58 GMT Message-Id: <201506290131.t5T1Vwlt043917@socsvn.freebsd.org> X-Authentication-Warning: socsvn.freebsd.org: www set sender to sdouglas@FreeBSD.org using -f From: sdouglas@FreeBSD.org To: svn-soc-all@FreeBSD.org Subject: socsvn commit: r287708 - in soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve: . tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-soc-all@freebsd.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: SVN commit messages for the entire Summer of Code repository List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 29 Jun 2015 01:32:00 -0000 Author: sdouglas Date: Mon Jun 29 01:31:57 2015 New Revision: 287708 URL: http://svnweb.FreeBSD.org/socsvn/?view=rev&rev=287708 Log: TFTP and DHCP working on a specified tap interface. Added: soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/Makefile soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/alloc.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/bpf.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/clparse.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/conflex.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/convert.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient-script soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient-script.8 soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient-script.8.gz (contents, props changed) soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.8 soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.conf soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.conf.5 soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.conf.5.gz (contents, props changed) soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.leases.5 soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhclient.leases.5.gz (contents, props changed) soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhcp-options.5 soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhcp-options.5.gz (contents, props changed) soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhcp.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhcp.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhcpd.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dhctoken.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/dispatch.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/easytftp.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/errwarn.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/hash.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/inet.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/options.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/packet.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/parse.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/privsep.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/privsep.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/pxebhyve.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/search_replace.pl soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tables.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tests/ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tests/Makefile soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tests/fake.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tests/option-domain-search.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tree.c soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/tree.h soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/userboot_dhclient.h Added: soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/Makefile ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/Makefile Mon Jun 29 01:31:57 2015 (r287708) @@ -0,0 +1,54 @@ +# $OpenBSD: Makefile,v 1.9 2004/05/04 12:52:05 henning Exp $ +# $FreeBSD: head/sbin/dhclient/Makefile 275030 2014-11-25 11:23:12Z bapt $ +# +# 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 +SRCS= ../../libexec/tftpd/tftp-file.c ../../libexec/tftpd/tftp-io.c ../../libexec/tftpd/tftp-options.c ../../libexec/tftpd/tftp-transfer.c +SRCS+= ../../libexec/tftpd/tftp-utils.c ../../usr.bin/tftp/tftp.c +SRCS+= clparse.c alloc.c dispatch.c hash.c bpf.c options.c \ + tree.c conflex.c errwarn.c inet.c packet.c convert.c tables.c \ + parse.c privsep.c +SRCS+= pxebhyve.c +PROG= pxebhyve +MAN= dhclient.8 +SCRIPTS=dhclient-script +LIBADD= util +WARNS?= 2 +CFLAGS+=-I../../usr.bin/tftp/ +CFLAGS+= -I../../libexec/tftpd/ +CPATH=../../libexec/tftpd/ ../../usr.bin/tftp/ + +.if ${MK_TESTS} != "no" +SUBDIR+= tests +.endif + +.include Added: soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/alloc.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/alloc.c Mon Jun 29 01:31:57 2015 (r287708) @@ -0,0 +1,79 @@ +/* $OpenBSD: alloc.c,v 1.9 2004/05/04 20:28:40 deraadt Exp $ */ + +/* Memory allocation... */ + +/* + * Copyright (c) 1995, 1996, 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 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 +__FBSDID("$FreeBSD: head/sbin/dhclient/alloc.c 149399 2005-08-23 23:59:55Z brooks $"); + +#include "dhcpd.h" + +struct string_list * +new_string_list(size_t size) +{ + struct string_list *rval; + + rval = calloc(1, sizeof(struct string_list) + size); + if (rval != NULL) + rval->string = ((char *)rval) + sizeof(struct string_list); + return (rval); +} + +struct hash_table * +new_hash_table(int count) +{ + struct hash_table *rval; + + rval = calloc(1, sizeof(struct hash_table) - + (DEFAULT_HASH_SIZE * sizeof(struct hash_bucket *)) + + (count * sizeof(struct hash_bucket *))); + if (rval == NULL) + return (NULL); + rval->hash_count = count; + return (rval); +} + +struct hash_bucket * +new_hash_bucket(void) +{ + struct hash_bucket *rval = calloc(1, sizeof(struct hash_bucket)); + + return (rval); +} Added: soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/bpf.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/bpf.c Mon Jun 29 01:31:57 2015 (r287708) @@ -0,0 +1,485 @@ +/* $OpenBSD: bpf.c,v 1.13 2004/05/05 14:28:58 deraadt 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 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 +__FBSDID("$FreeBSD: head/sbin/dhclient/bpf.c 267914 2014-06-26 13:57:44Z pjd $"); + +#include "dhcpd.h" +#include "privsep.h" +#include +#include +#include + +#include +#include +#include +#include +#include + +#define BPF_FORMAT "/dev/bpf%d" + +/* + * Called by get_interface_list for each interface that's discovered. + * Opens a packet filter for each interface and adds it to the select + * mask. + */ +int +if_register_bpf(struct interface_info *info, int flags) +{ + char filename[50]; + int sock, b; + + /* Open a BPF device */ + for (b = 0;; b++) { + snprintf(filename, sizeof(filename), BPF_FORMAT, b); + sock = open(filename, flags); + if (sock < 0) { + if (errno == EBUSY) + continue; + else + error("Can't find free bpf: %m"); + } else + break; + } + + /* Set the BPF device to point at this interface. */ + if (ioctl(sock, BIOCSETIF, info->ifp) < 0) + error("Can't attach interface %s to bpf device %s: %m", + info->name, filename); + + return (sock); +} + +/* + * 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, (u_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); + +void +if_register_send(struct interface_info *info) +{ + cap_rights_t rights; + struct bpf_version v; + struct bpf_program p; + int sock, on = 1; + + /* Open a BPF device and hang it on this interface... */ + info->wfdesc = if_register_bpf(info, O_WRONLY); + + /* Make sure the BPF version is in range... */ + if (ioctl(info->wfdesc, BIOCVERSION, &v) < 0) + error("Can't get BPF version: %m"); + + if (v.bv_major != BPF_MAJOR_VERSION || + v.bv_minor < BPF_MINOR_VERSION) + error("Kernel BPF version out of range - recompile dhcpd!"); + + /* 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(info->wfdesc, BIOCSETWF, &p) < 0) + error("Can't install write filter program: %m"); + + if (ioctl(info->wfdesc, BIOCLOCK, NULL) < 0) + error("Cannot lock bpf"); + + cap_rights_init(&rights, CAP_WRITE); + if (cap_rights_limit(info->wfdesc, &rights) < 0 && errno != ENOSYS) + error("Can't limit bpf descriptor: %m"); + + /* + * Use raw socket for unicast send. + */ + if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) + error("socket(SOCK_RAW): %m"); + if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, &on, + sizeof(on)) == -1) + error("setsockopt(IP_HDRINCL): %m"); + info->ufdesc = sock; +} + +/* + * Packet filter program... + * + * XXX: Changes to the filter program may require changes to the + * constant offsets used in if_register_send 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, (u_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); + +void +if_register_receive(struct interface_info *info) +{ + static const unsigned long cmds[2] = { SIOCGIFFLAGS, SIOCGIFMEDIA }; + cap_rights_t rights; + struct bpf_version v; + struct bpf_program p; + int flag = 1, sz; + + /* Open a BPF device and hang it on this interface... */ + info->rfdesc = if_register_bpf(info, O_RDONLY); + + /* Make sure the BPF version is in range... */ + if (ioctl(info->rfdesc, BIOCVERSION, &v) < 0) + error("Can't get BPF version: %m"); + + if (v.bv_major != BPF_MAJOR_VERSION || + v.bv_minor < BPF_MINOR_VERSION) + error("Kernel BPF version out of range - recompile dhcpd!"); + + /* + * 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(info->rfdesc, BIOCIMMEDIATE, &flag) < 0) + error("Can't set immediate mode on bpf device: %m"); + + /* Get the required BPF buffer length from the kernel. */ + if (ioctl(info->rfdesc, BIOCGBLEN, &sz) < 0) + error("Can't get bpf buffer length: %m"); + info->rbuf_max = sz; + info->rbuf = malloc(info->rbuf_max); + if (!info->rbuf) + error("Can't allocate %lu bytes for bpf input buffer.", + (unsigned long)info->rbuf_max); + info->rbuf_offset = 0; + info->rbuf_len = 0; + + /* 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... + * + * XXX: changes to filter program may require changes to the + * insn number(s) used below! + */ + dhcp_bpf_filter[8].k = LOCAL_PORT; + + if (ioctl(info->rfdesc, BIOCSETF, &p) < 0) + error("Can't install packet filter program: %m"); + + if (ioctl(info->rfdesc, BIOCLOCK, NULL) < 0) + error("Cannot lock bpf"); + + cap_rights_init(&rights, CAP_IOCTL, CAP_EVENT, CAP_READ); + if (cap_rights_limit(info->rfdesc, &rights) < 0 && errno != ENOSYS) + error("Can't limit bpf descriptor: %m"); + if (cap_ioctls_limit(info->rfdesc, cmds, 2) < 0 && errno != ENOSYS) + error("Can't limit ioctls for bpf descriptor: %m"); +} + +void +send_packet_unpriv(int privfd, struct dhcp_packet *raw, size_t len, + struct in_addr from, struct in_addr to) +{ + struct imsg_hdr hdr; + struct buf *buf; + int errs; + + hdr.code = IMSG_SEND_PACKET; + hdr.len = sizeof(hdr) + + sizeof(size_t) + len + + sizeof(from) + sizeof(to); + + if ((buf = buf_open(hdr.len)) == NULL) + error("buf_open: %m"); + + errs = 0; + errs += buf_add(buf, &hdr, sizeof(hdr)); + errs += buf_add(buf, &len, sizeof(len)); + errs += buf_add(buf, raw, len); + errs += buf_add(buf, &from, sizeof(from)); + errs += buf_add(buf, &to, sizeof(to)); + if (errs) + error("buf_add: %m"); + + if (buf_close(privfd, buf) == -1) + error("buf_close: %m"); +} + +void +send_packet_priv(struct interface_info *interface, struct imsg_hdr *hdr, int fd) +{ + unsigned char buf[256]; + struct iovec iov[2]; + struct msghdr msg; + struct dhcp_packet raw; + size_t len; + struct in_addr from, to; + int result, bufp = 0; + + if (hdr->len < sizeof(*hdr) + sizeof(size_t)) + error("corrupted message received"); + buf_read(fd, &len, sizeof(len)); + if (hdr->len != sizeof(*hdr) + sizeof(size_t) + len + + sizeof(from) + sizeof(to)) { + error("corrupted message received"); + } + if (len > sizeof(raw)) + error("corrupted message received"); + buf_read(fd, &raw, len); + buf_read(fd, &from, sizeof(from)); + buf_read(fd, &to, sizeof(to)); + + /* Assemble the headers... */ + if (to.s_addr == INADDR_BROADCAST) + assemble_hw_header(interface, buf, &bufp); + assemble_udp_ip_header(buf, &bufp, from.s_addr, to.s_addr, + htons(REMOTE_PORT), (unsigned char *)&raw, len); + + iov[0].iov_base = buf; + iov[0].iov_len = bufp; + iov[1].iov_base = &raw; + iov[1].iov_len = len; + + /* Fire it off */ + if (to.s_addr == INADDR_BROADCAST) + result = writev(interface->wfdesc, iov, 2); + else { + struct sockaddr_in sato; + + sato.sin_addr = to; + sato.sin_port = htons(REMOTE_PORT); + sato.sin_family = AF_INET; + sato.sin_len = sizeof(sato); + + memset(&msg, 0, sizeof(msg)); + msg.msg_name = (struct sockaddr *)&sato; + msg.msg_namelen = sizeof(sato); + msg.msg_iov = iov; + msg.msg_iovlen = 2; + result = sendmsg(interface->ufdesc, &msg, 0); + } + + if (result < 0) + warning("send_packet: %m"); +} + +ssize_t +dhcp_receive_packet(struct interface_info *interface, unsigned char *buf, + size_t len, struct sockaddr_in *from, struct hardware *hfrom) +{ + int length = 0, offset = 0; + struct bpf_hdr hdr; + + /* + * All this complexity is because BPF doesn't guarantee that + * only one packet will be returned at a time. We're getting + * what we deserve, though - this is a terrible abuse of the BPF + * interface. Sigh. + */ + + /* Process packets until we get one we can return or until we've + * done a read and gotten nothing we can return... + */ + do { + /* If the buffer is empty, fill it. */ + if (interface->rbuf_offset >= interface->rbuf_len) { + length = read(interface->rfdesc, interface->rbuf, + interface->rbuf_max); + if (length <= 0) + return (length); + interface->rbuf_offset = 0; + interface->rbuf_len = length; + } + + /* + * If there isn't room for a whole bpf header, something + * went wrong, but we'll ignore it and hope it goes + * away... XXX + */ + if (interface->rbuf_len - interface->rbuf_offset < + sizeof(hdr)) { + interface->rbuf_offset = interface->rbuf_len; + continue; + } + + /* Copy out a bpf header... */ + memcpy(&hdr, &interface->rbuf[interface->rbuf_offset], + sizeof(hdr)); + + /* + * If the bpf header plus data doesn't fit in what's + * left of the buffer, stick head in sand yet again... + */ + if (interface->rbuf_offset + hdr.bh_hdrlen + hdr.bh_caplen > + interface->rbuf_len) { + interface->rbuf_offset = interface->rbuf_len; + continue; + } + + /* Skip over the BPF header... */ + interface->rbuf_offset += hdr.bh_hdrlen; + + /* + * If the captured data wasn't the whole packet, or if + * the packet won't fit in the input buffer, all we can + * do is drop it. + */ + if (hdr.bh_caplen != hdr.bh_datalen) { + interface->rbuf_offset = + BPF_WORDALIGN(interface->rbuf_offset + + hdr.bh_caplen); + continue; + } + + /* Decode the physical header... */ + offset = decode_hw_header(interface->rbuf, + interface->rbuf_offset, hfrom); + + /* + * If a physical layer checksum failed (dunno of any + * physical layer that supports this, but WTH), skip + * this packet. + */ + if (offset < 0) { + interface->rbuf_offset = + BPF_WORDALIGN(interface->rbuf_offset + + hdr.bh_caplen); + continue; + } + interface->rbuf_offset += offset; + hdr.bh_caplen -= offset; + + /* Decode the IP and UDP headers... */ + offset = decode_udp_ip_header(interface->rbuf, + interface->rbuf_offset, from, NULL, hdr.bh_caplen); + + /* If the IP or UDP checksum was bad, skip the packet... */ + if (offset < 0) { + interface->rbuf_offset = + BPF_WORDALIGN(interface->rbuf_offset + + hdr.bh_caplen); + continue; + } + interface->rbuf_offset += offset; + hdr.bh_caplen -= offset; + + /* + * If there's not enough room to stash the packet data, + * we have to skip it (this shouldn't happen in real + * life, though). + */ + if (hdr.bh_caplen > len) { + interface->rbuf_offset = + BPF_WORDALIGN(interface->rbuf_offset + + hdr.bh_caplen); + continue; + } + + /* Copy out the data in the packet... */ + memcpy(buf, interface->rbuf + interface->rbuf_offset, + hdr.bh_caplen); + interface->rbuf_offset = + BPF_WORDALIGN(interface->rbuf_offset + + hdr.bh_caplen); + return (hdr.bh_caplen); + } while (!length); + return (0); +} Added: soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/clparse.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ soc2015/sdouglas/pxebhyve-head/usr.sbin/pxebhyve/clparse.c Mon Jun 29 01:31:57 2015 (r287708) @@ -0,0 +1,951 @@ +/* $OpenBSD: clparse.c,v 1.18 2004/09/15 18:15:18 henning 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 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 +__FBSDID("$FreeBSD: head/sbin/dhclient/clparse.c 252506 2013-07-02 13:24:37Z bms $"); + +#include "dhcpd.h" +#include "dhctoken.h" + +struct client_config top_level_config; +struct interface_info *dummy_interfaces; +extern struct interface_info *ifi; + +char client_script_name[] = "/sbin/dhclient-script"; + +/* + * client-conf-file :== client-declarations EOF + * client-declarations :== + * | client-declaration + * | client-declarations client-declaration + */ +int +read_client_conf(void) +{ + FILE *cfile; + char *val; + int token; + struct client_config *config; + + new_parse(path_dhclient_conf); + + /* Set up the initial dhcp option universe. */ + initialize_universes(); + + /* Initialize the top level client configuration. */ + memset(&top_level_config, 0, sizeof(top_level_config)); + + /* Set some defaults... */ + top_level_config.timeout = 60; + top_level_config.select_interval = 0; + top_level_config.reboot_timeout = 10; + top_level_config.retry_interval = 300; + top_level_config.backoff_cutoff = 15; + top_level_config.initial_interval = 3; + top_level_config.bootp_policy = ACCEPT; + top_level_config.script_name = client_script_name; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_SUBNET_MASK; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_BROADCAST_ADDRESS; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_TIME_OFFSET; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_CLASSLESS_ROUTES; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_ROUTERS; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_DOMAIN_NAME; + top_level_config.requested_options + [top_level_config.requested_option_count++] = + DHO_DOMAIN_NAME_SERVERS; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_HOST_NAME; + top_level_config.requested_options + [top_level_config.requested_option_count++] = DHO_DOMAIN_SEARCH; + + if ((cfile = fopen(path_dhclient_conf, "r")) != NULL) { + do { + token = peek_token(&val, cfile); + if (token == EOF) + break; + parse_client_statement(cfile, NULL, &top_level_config); + } while (1); + token = next_token(&val, cfile); /* Clear the peek buffer */ + fclose(cfile); + } + + /* + * Set up state and config structures for clients that don't + * have per-interface configuration declarations. + */ + config = NULL; + if (!ifi->client) { + ifi->client = malloc(sizeof(struct client_state)); + if (!ifi->client) + error("no memory for client state."); + memset(ifi->client, 0, sizeof(*(ifi->client))); + } + if (!ifi->client->config) { + if (!config) { + config = malloc(sizeof(struct client_config)); + if (!config) + error("no memory for client config."); + memcpy(config, &top_level_config, + sizeof(top_level_config)); + } + ifi->client->config = config; + } + + return (!warnings_occurred); +} + +/* + * lease-file :== client-lease-statements EOF + * client-lease-statements :== + * | client-lease-statements LEASE client-lease-statement + */ +void +read_client_leases(void) +{ + FILE *cfile; + char *val; + int token; + + new_parse(path_dhclient_db); + + /* Open the lease file. If we can't open it, just return - + we can safely trust the server to remember our state. */ + if ((cfile = fopen(path_dhclient_db, "r")) == NULL) + return; + do { + token = next_token(&val, cfile); + if (token == EOF) + break; + if (token != LEASE) { + warning("Corrupt lease file - possible data loss!"); + skip_to_semi(cfile); + break; + } else + parse_client_lease_statement(cfile, 0); + + } while (1); + fclose(cfile); +} + +/* + * client-declaration :== + * SEND option-decl | + * DEFAULT option-decl | + * SUPERSEDE option-decl | + * PREPEND option-decl | + * APPEND option-decl | + * hardware-declaration | + * REQUEST option-list | + * REQUIRE option-list | + * TIMEOUT number | + * RETRY number | + * REBOOT number | + * SELECT_TIMEOUT number | + * SCRIPT string | + * interface-declaration | + * LEASE client-lease-statement | + * ALIAS client-lease-statement + */ +void +parse_client_statement(FILE *cfile, struct interface_info *ip, + struct client_config *config) +{ + int token; + char *val; + struct option *option; + + switch (next_token(&val, cfile)) { + case SEND: + parse_option_decl(cfile, &config->send_options[0]); + return; + case DEFAULT: + option = parse_option_decl(cfile, &config->defaults[0]); + if (option) + config->default_actions[option->code] = ACTION_DEFAULT; + return; + case SUPERSEDE: + option = parse_option_decl(cfile, &config->defaults[0]); + if (option) + config->default_actions[option->code] = + ACTION_SUPERSEDE; + return; + case APPEND: + option = parse_option_decl(cfile, &config->defaults[0]); + if (option) + config->default_actions[option->code] = ACTION_APPEND; + return; + case PREPEND: + option = parse_option_decl(cfile, &config->defaults[0]); + if (option) + config->default_actions[option->code] = ACTION_PREPEND; + return; + case MEDIA: + parse_string_list(cfile, &config->media, 1); + return; + case HARDWARE: + if (ip) + parse_hardware_param(cfile, &ip->hw_address); + else { + parse_warn("hardware address parameter %s", + "not allowed here."); + skip_to_semi(cfile); + } + return; + case REQUEST: + config->requested_option_count = + parse_option_list(cfile, config->requested_options); + return; + case REQUIRE: + memset(config->required_options, 0, + sizeof(config->required_options)); + parse_option_list(cfile, config->required_options); + return; + case TIMEOUT: + parse_lease_time(cfile, &config->timeout); + return; + case RETRY: + parse_lease_time(cfile, &config->retry_interval); + return; + case SELECT_TIMEOUT: + parse_lease_time(cfile, &config->select_interval); + return; + case REBOOT: + parse_lease_time(cfile, &config->reboot_timeout); + return; + case BACKOFF_CUTOFF: + parse_lease_time(cfile, &config->backoff_cutoff); + return; + case INITIAL_INTERVAL: + parse_lease_time(cfile, &config->initial_interval); + return; + case SCRIPT: + config->script_name = parse_string(cfile); + return; + case INTERFACE: + if (ip) + parse_warn("nested interface declaration."); + parse_interface_declaration(cfile, config); + return; + case LEASE: + parse_client_lease_statement(cfile, 1); + return; + case ALIAS: + parse_client_lease_statement(cfile, 2); + return; + case REJECT: + parse_reject_statement(cfile, config); + return; + default: + parse_warn("expecting a statement."); + skip_to_semi(cfile); + break; + } + token = next_token(&val, cfile); + if (token != SEMI) { + parse_warn("semicolon expected."); + skip_to_semi(cfile); + } +} + +int +parse_X(FILE *cfile, u_int8_t *buf, int max) +{ + int token; + char *val; + int len; + + token = peek_token(&val, cfile); + if (token == NUMBER_OR_NAME || token == NUMBER) { + len = 0; + do { + token = next_token(&val, cfile); + if (token != NUMBER && token != NUMBER_OR_NAME) { + parse_warn("expecting hexadecimal constant."); + skip_to_semi(cfile); + return (0); + } + convert_num(&buf[len], val, 16, 8); + if (len++ > max) { + parse_warn("hexadecimal constant too long."); + skip_to_semi(cfile); + return (0); + } + token = peek_token(&val, cfile); + if (token == COLON) + token = next_token(&val, cfile); + } while (token == COLON); + val = (char *)buf; + } else if (token == STRING) { + token = next_token(&val, cfile); + len = strlen(val); + if (len + 1 > max) { + parse_warn("string constant too long."); + skip_to_semi(cfile); + return (0); + } + memcpy(buf, val, len + 1); + } else { + parse_warn("expecting string or hexadecimal data"); + skip_to_semi(cfile); + return (0); + } + return (len); +} + +/* + * option-list :== option_name | + * option_list COMMA option_name + */ +int +parse_option_list(FILE *cfile, u_int8_t *list) +{ + int ix, i; + int token; + char *val; + + ix = 0; + do { + token = next_token(&val, cfile); + if (!is_identifier(token)) { + parse_warn("expected option name."); + skip_to_semi(cfile); + return (0); + } + for (i = 0; i < 256; i++) + if (!strcasecmp(dhcp_options[i].name, val)) + break; + + if (i == 256) { + parse_warn("%s: unexpected option name.", val); + skip_to_semi(cfile); + return (0); + } + list[ix++] = i; + if (ix == 256) { + parse_warn("%s: too many options.", val); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***