diff options
author | obrien <obrien@FreeBSD.org> | 1999-02-10 09:10:13 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1999-02-10 09:10:13 +0000 |
commit | 117fbe9a9bc304e0e099d61d60b1a5d016afff04 (patch) | |
tree | 238471ef1d73dff2645de45ab083d2123bf56b83 /contrib/isc-dhcp/common | |
download | FreeBSD-src-117fbe9a9bc304e0e099d61d60b1a5d016afff04.zip FreeBSD-src-117fbe9a9bc304e0e099d61d60b1a5d016afff04.tar.gz |
Virgin import of ISC-DHCP v2.0b1pl6
Diffstat (limited to 'contrib/isc-dhcp/common')
22 files changed, 8448 insertions, 0 deletions
diff --git a/contrib/isc-dhcp/common/alloc.c b/contrib/isc-dhcp/common/alloc.c new file mode 100644 index 0000000..172fcea --- /dev/null +++ b/contrib/isc-dhcp/common/alloc.c @@ -0,0 +1,329 @@ +/* alloc.c + + Memory allocation... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: alloc.c,v 1.13 1997/05/09 07:56:13 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +struct dhcp_packet *dhcp_free_list; +struct packet *packet_free_list; + +VOIDPTR dmalloc (size, name) + int size; + char *name; +{ + VOIDPTR foo = (VOIDPTR)malloc (size); + if (!foo) + warn ("No memory for %s.", name); + memset (foo, 0, size); + return foo; +} + +void dfree (ptr, name) + VOIDPTR ptr; + char *name; +{ + if (!ptr) { + warn ("dfree %s: free on null pointer.", name); + return; + } + free (ptr); +} + +struct packet *new_packet (name) + char *name; +{ + struct packet *rval; + rval = (struct packet *)dmalloc (sizeof (struct packet), name); + return rval; +} + +struct dhcp_packet *new_dhcp_packet (name) + char *name; +{ + struct dhcp_packet *rval; + rval = (struct dhcp_packet *)dmalloc (sizeof (struct dhcp_packet), + name); + return rval; +} + +struct tree *new_tree (name) + char *name; +{ + struct tree *rval = dmalloc (sizeof (struct tree), name); + return rval; +} + +struct tree_cache *free_tree_caches; + +struct tree_cache *new_tree_cache (name) + char *name; +{ + struct tree_cache *rval; + + if (free_tree_caches) { + rval = free_tree_caches; + free_tree_caches = + (struct tree_cache *)(rval -> value); + } else { + rval = dmalloc (sizeof (struct tree_cache), name); + if (!rval) + error ("unable to allocate tree cache for %s.", name); + } + return rval; +} + +struct hash_table *new_hash_table (count, name) + int count; + char *name; +{ + struct hash_table *rval = dmalloc (sizeof (struct hash_table) + - (DEFAULT_HASH_SIZE + * sizeof (struct hash_bucket *)) + + (count + * sizeof (struct hash_bucket *)), + name); + rval -> hash_count = count; + return rval; +} + +struct hash_bucket *new_hash_bucket (name) + char *name; +{ + struct hash_bucket *rval = dmalloc (sizeof (struct hash_bucket), name); + return rval; +} + +struct lease *new_leases (n, name) + int n; + char *name; +{ + struct lease *rval = dmalloc (n * sizeof (struct lease), name); + return rval; +} + +struct lease *new_lease (name) + char *name; +{ + struct lease *rval = dmalloc (sizeof (struct lease), name); + return rval; +} + +struct subnet *new_subnet (name) + char *name; +{ + struct subnet *rval = dmalloc (sizeof (struct subnet), name); + return rval; +} + +struct class *new_class (name) + char *name; +{ + struct class *rval = dmalloc (sizeof (struct class), name); + return rval; +} + +struct shared_network *new_shared_network (name) + char *name; +{ + struct shared_network *rval = + dmalloc (sizeof (struct shared_network), name); + return rval; +} + +struct group *new_group (name) + char *name; +{ + struct group *rval = + dmalloc (sizeof (struct group), name); + return rval; +} + +struct protocol *new_protocol (name) + char *name; +{ + struct protocol *rval = dmalloc (sizeof (struct protocol), name); + return rval; +} + +struct lease_state *free_lease_states; + +struct lease_state *new_lease_state (name) + char *name; +{ + struct lease_state *rval; + + if (free_lease_states) { + rval = free_lease_states; + free_lease_states = + (struct lease_state *)(free_lease_states -> next); + } else { + rval = dmalloc (sizeof (struct lease_state), name); + } + return rval; +} + +struct domain_search_list *new_domain_search_list (name) + char *name; +{ + struct domain_search_list *rval = + dmalloc (sizeof (struct domain_search_list), name); + return rval; +} + +struct name_server *new_name_server (name) + char *name; +{ + struct name_server *rval = + dmalloc (sizeof (struct name_server), name); + return rval; +} + +void free_name_server (ptr, name) + struct name_server *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_domain_search_list (ptr, name) + struct domain_search_list *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_lease_state (ptr, name) + struct lease_state *ptr; + char *name; +{ + ptr -> next = free_lease_states; + free_lease_states = ptr; +} + +void free_protocol (ptr, name) + struct protocol *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_group (ptr, name) + struct group *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_shared_network (ptr, name) + struct shared_network *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_class (ptr, name) + struct class *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_subnet (ptr, name) + struct subnet *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_lease (ptr, name) + struct lease *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_hash_bucket (ptr, name) + struct hash_bucket *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_hash_table (ptr, name) + struct hash_table *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_tree_cache (ptr, name) + struct tree_cache *ptr; + char *name; +{ + ptr -> value = (unsigned char *)free_tree_caches; + free_tree_caches = ptr; +} + +void free_packet (ptr, name) + struct packet *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_dhcp_packet (ptr, name) + struct dhcp_packet *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} + +void free_tree (ptr, name) + struct tree *ptr; + char *name; +{ + dfree ((VOIDPTR)ptr, name); +} diff --git a/contrib/isc-dhcp/common/bpf.c b/contrib/isc-dhcp/common/bpf.c new file mode 100644 index 0000000..e47aa1f --- /dev/null +++ b/contrib/isc-dhcp/common/bpf.c @@ -0,0 +1,386 @@ +/* bpf.c + + BPF socket interface code, originally contributed by Archie Cobbs. */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: bpf.c,v 1.19 1997/10/20 21:47:13 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#if defined (USE_BPF_SEND) || defined (USE_BPF_RECEIVE) +#include <sys/ioctl.h> +#include <sys/uio.h> + +#include <net/bpf.h> +#ifdef NEED_OSF_PFILT_HACKS +#include <net/pfilt.h> +#endif +#include <netinet/in_systm.h> +#include "includes/netinet/ip.h" +#include "includes/netinet/udp.h" +#include "includes/netinet/if_ether.h" + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_BPF_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +} +#endif + +#ifdef USE_BPF_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +} +#endif + +/* 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 (info) + struct interface_info *info; +{ + int sock; + char filename[50]; + int b; + + /* Open a BPF device */ + for (b = 0; 1; b++) { +#ifndef NO_SNPRINTF + snprintf(filename, sizeof(filename), BPF_FORMAT, b); +#else + sprintf(filename, BPF_FORMAT, b); +#endif + sock = open (filename, O_RDWR, 0); + 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; +} +#endif /* USE_BPF_SEND || USE_BPF_RECEIVE */ + +#ifdef USE_BPF_SEND +void if_register_send (info) + struct interface_info *info; +{ + /* If we're using the bpf API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_BPF_RECEIVE + info -> wfdesc = if_register_bpf (info, interface); +#else + info -> wfdesc = info -> rfdesc; +#endif + if (!quiet_interface_discovery) + note ("Sending on BPF/%s/%s/%s", + info -> name, + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_BPF_SEND */ + +#ifdef USE_BPF_RECEIVE +/* 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! XXX */ + +struct bpf_insn 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), +}; + +void if_register_receive (info) + struct interface_info *info; +{ + int flag = 1; + struct bpf_version v; + u_int32_t addr; + struct bpf_program p; + u_int32_t bits; + + /* Open a BPF device and hang it on this interface... */ + info -> rfdesc = if_register_bpf (info); + + /* 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"); + +#ifdef NEED_OSF_PFILT_HACKS + /* Allow the copyall flag to be set... */ + if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) + error ("Can't set ALLOWCOPYALL: %m"); + + /* Clear all the packet filter mode bits first... */ + bits = 0; + if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) + error ("Can't clear pfilt bits: %m"); + + /* Set the ENBATCH, ENCOPYALL, ENBPFHDR bits... */ + bits = ENBATCH | ENCOPYALL | ENBPFHDR; + if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) + error ("Can't set ENBATCH|ENCOPYALL|ENBPFHDR: %m"); +#endif + /* Get the required BPF buffer length from the kernel. */ + if (ioctl (info -> rfdesc, BIOCGBLEN, &info -> rbuf_max) < 0) + error ("Can't get bpf buffer length: %m"); + info -> rbuf = malloc (info -> rbuf_max); + if (!info -> rbuf) + error ("Can't allocate %d bytes for bpf input buffer."); + info -> rbuf_offset = 0; + info -> rbuf_len = 0; + + /* Set up the bpf filter program structure. */ + p.bf_len = sizeof filter / sizeof (struct bpf_insn); + p.bf_insns = filter; + + /* Patch the server port into the BPF program... + XXX changes to filter program may require changes + to the insn number(s) used below! XXX */ + filter [8].k = ntohs (local_port); + + if (ioctl (info -> rfdesc, BIOCSETF, &p) < 0) + error ("Can't install packet filter program: %m"); + if (!quiet_interface_discovery) + note ("Listening on BPF/%s/%s/%s", + info -> name, + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_BPF_RECEIVE */ + +#ifdef USE_BPF_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + int bufp = 0; + unsigned char buf [256]; + struct iovec iov [2]; + + /* Assemble the headers... */ + assemble_hw_header (interface, buf, &bufp, hto); + assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + to -> sin_addr.s_addr, to -> sin_port, + (unsigned char *)raw, len); + + /* Fire it off */ + iov [0].iov_base = (char *)buf; + iov [0].iov_len = bufp; + iov [1].iov_base = (char *)raw; + iov [1].iov_len = len; + + return writev(interface -> wfdesc, iov, 2); +} +#endif /* USE_BPF_SEND */ + +#ifdef USE_BPF_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + int length = 0; + int 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; + } + + /* 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 += + hdr.bh_hdrlen = hdr.bh_caplen; + continue; + } + + /* Skip over the BPF header... */ + interface -> rbuf_offset += hdr.bh_hdrlen; + + /* Decode the physical header... */ + offset = decode_hw_header (interface, + 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 += hdr.bh_caplen; + continue; + } + interface -> rbuf_offset += offset; + hdr.bh_caplen -= offset; + + /* Decode the IP and UDP headers... */ + offset = decode_udp_ip_header (interface, + interface -> rbuf, + interface -> rbuf_offset, + from, + (unsigned char *)0, + hdr.bh_caplen); + + /* If the IP or UDP checksum was bad, skip the packet... */ + if (offset < 0) { + 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 += hdr.bh_caplen; + continue; + } + + /* Copy out the data in the packet... */ + memcpy (buf, interface -> rbuf + interface -> rbuf_offset, + hdr.bh_caplen); + interface -> rbuf_offset += hdr.bh_caplen; + return hdr.bh_caplen; + } while (!length); + return 0; +} +#endif diff --git a/contrib/isc-dhcp/common/conflex.c b/contrib/isc-dhcp/common/conflex.c new file mode 100644 index 0000000..eedfa05 --- /dev/null +++ b/contrib/isc-dhcp/common/conflex.c @@ -0,0 +1,548 @@ +/* conflex.c + + Lexical scanner for dhcpd 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: conflex.c,v 1.29 1997/10/29 18:32:53 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include "dhctoken.h" +#include <ctype.h> + +int lexline; +int lexchar; +char *token_line; +char *prev_line; +char *cur_line; +char *tlname; +int eol_token; + +static char line1 [81]; +static char line2 [81]; +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]; + +#ifdef OLD_LEXER +char comments [4096]; +int comment_index; +#endif + + +static int get_char PROTO ((FILE *)); +static int get_token PROTO ((FILE *)); +static void skip_to_eol PROTO ((FILE *)); +static int read_string PROTO ((FILE *)); +static int read_number PROTO ((int, FILE *)); +static int read_num_or_name PROTO ((int, FILE *)); +static int intern PROTO ((char *, int)); + +void new_parse (name) + char *name; +{ + tlname = name; + lpos = line = 1; + cur_line = line1; + prev_line = line2; + token_line = cur_line; + cur_line [0] = prev_line [0] = 0; + warnings_occurred = 0; +} + +static int get_char (cfile) + FILE *cfile; +{ + int c = getc (cfile); + if (!ugflag) { + if (c == EOL) { + if (cur_line == line1) { + cur_line = line2; + prev_line = line1; + } else { + cur_line = line2; + prev_line = line1; + } + line++; + lpos = 1; + cur_line [0] = 0; + } else if (c != EOF) { + if (lpos <= 81) { + cur_line [lpos - 1] = c; + cur_line [lpos] = 0; + } + lpos++; + } + } else + ugflag = 0; + return c; +} + +static int get_token (cfile) + FILE *cfile; +{ + int c; + int ttok; + static char tb [2]; + int l, p, u; + + do { + l = line; + p = lpos; + u = ugflag; + + c = get_char (cfile); +#ifdef OLD_LEXER + if (c == '\n' && p == 1 && !u + && comment_index < sizeof comments) + comments [comment_index++] = '\n'; +#endif + + if (!(c == '\n' && eol_token) && isascii (c) && isspace (c)) + continue; + if (c == '#') { +#ifdef OLD_LEXER + if (comment_index < sizeof comments) + comments [comment_index++] = '#'; +#endif + skip_to_eol (cfile); + continue; + } + if (c == '"') { + lexline = l; + lexchar = p; + ttok = read_string (cfile); + break; + } + if ((isascii (c) && isdigit (c)) || c == '-') { + lexline = l; + lexchar = p; + ttok = read_number (c, cfile); + break; + } else if (isascii (c) && isalpha (c)) { + lexline = l; + lexchar = p; + ttok = read_num_or_name (c, cfile); + break; + } else { + lexline = l; + lexchar = p; + tb [0] = c; + tb [1] = 0; + tval = tb; + ttok = c; + break; + } + } while (1); + return ttok; +} + +int next_token (rval, cfile) + char **rval; + FILE *cfile; +{ + int rv; + + if (token) { + 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) + *rval = tval; +#ifdef DEBUG_TOKENS + fprintf (stderr, "%s:%d ", tval, rv); +#endif + return rv; +} + +int peek_token (rval, cfile) + char **rval; + FILE *cfile; +{ + int x; + + if (!token) { + 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) + *rval = tval; +#ifdef DEBUG_TOKENS + fprintf (stderr, "(%s:%d) ", tval, token); +#endif + return token; +} + +static void skip_to_eol (cfile) + FILE *cfile; +{ + int c; + do { + c = get_char (cfile); + if (c == EOF) + return; +#ifdef OLD_LEXER + if (comment_index < sizeof (comments)) + comments [comment_index++] = c; +#endif + if (c == EOL) { + return; + } + } while (1); +} + +static int read_string (cfile) + FILE *cfile; +{ + int i; + int bs = 0; + int c; + + for (i = 0; i < sizeof tokbuf; i++) { + c = get_char (cfile); + if (c == EOF) { + parse_warn ("eof in string constant"); + break; + } + if (bs) { + bs = 0; + tokbuf [i] = c; + } else if (c == '\\') + bs = 1; + else if (c == '"') + break; + else + tokbuf [i] = c; + } + /* Normally, I'd feel guilty about this, but we're talking about + strings that'll fit in a DHCP packet here... */ + if (i == sizeof tokbuf) { + parse_warn ("string constant larger than internal buffer"); + --i; + } + tokbuf [i] = 0; + tval = tokbuf; + return STRING; +} + +static int read_number (c, cfile) + int c; + FILE *cfile; +{ + int seenx = 0; + int i = 0; + int token = NUMBER; + + tokbuf [i++] = c; + for (; i < sizeof tokbuf; i++) { + c = get_char (cfile); + if (!seenx && c == 'x') { + seenx = 1; +#ifndef OLD_LEXER + } else if (isascii (c) && !isxdigit (c) && + (c == '-' || c == '_' || isalpha (c))) { + token = NAME; + } else if (isascii (c) && !isdigit (c) && isxdigit (c)) { + token = NUMBER_OR_NAME; +#endif + } else if (!isascii (c) || !isxdigit (c)) { + ungetc (c, cfile); + ugflag = 1; + break; + } + tokbuf [i] = c; + } + if (i == sizeof tokbuf) { + parse_warn ("numeric token larger than internal buffer"); + --i; + } + tokbuf [i] = 0; + tval = tokbuf; + return token; +} + +static int read_num_or_name (c, cfile) + int c; + FILE *cfile; +{ + int i = 0; + int rv = NUMBER_OR_NAME; + tokbuf [i++] = c; + for (; i < sizeof tokbuf; i++) { + c = get_char (cfile); + if (!isascii (c) || + (c != '-' && c != '_' && !isalnum (c))) { + ungetc (c, cfile); + ugflag = 1; + break; + } + if (!isxdigit (c)) + rv = NAME; + tokbuf [i] = c; + } + if (i == sizeof tokbuf) { + parse_warn ("token larger than internal buffer"); + --i; + } + tokbuf [i] = 0; + tval = tokbuf; + return intern (tval, rv); +} + +static int intern (atom, dfv) + char *atom; + int dfv; +{ + if (!isascii (atom [0])) + return dfv; + + switch (tolower (atom [0])) { + case 'a': + if (!strcasecmp (atom + 1, "ppend")) + return APPEND; + if (!strcasecmp (atom + 1, "llow")) + return ALLOW; + if (!strcasecmp (atom + 1, "lias")) + return ALIAS; + if (!strcasecmp (atom + 1, "bandoned")) + return ABANDONED; + break; + case 'b': + if (!strcasecmp (atom + 1, "ackoff-cutoff")) + return BACKOFF_CUTOFF; + if (!strcasecmp (atom + 1, "ootp")) + return BOOTP; + if (!strcasecmp (atom + 1, "ooting")) + return BOOTING; + if (!strcasecmp (atom + 1, "oot-unknown-clients")) + return BOOT_UNKNOWN_CLIENTS; + case 'c': + if (!strcasecmp (atom + 1, "lass")) + return CLASS; + if (!strcasecmp (atom + 1, "iaddr")) + return CIADDR; + if (!strcasecmp (atom + 1, "lient-identifier")) + return CLIENT_IDENTIFIER; + if (!strcasecmp (atom + 1, "lient-hostname")) + return CLIENT_HOSTNAME; + break; + case 'd': + if (!strcasecmp (atom + 1, "omain")) + return DOMAIN; + if (!strcasecmp (atom + 1, "eny")) + return DENY; + if (!strncasecmp (atom + 1, "efault", 6)) { + if (!atom [7]) + return DEFAULT; + if (!strcasecmp (atom + 7, "-lease-time")) + return DEFAULT_LEASE_TIME; + break; + } + if (!strncasecmp (atom + 1, "ynamic-bootp", 12)) { + if (!atom [13]) + return DYNAMIC_BOOTP; + if (!strcasecmp (atom + 13, "-lease-cutoff")) + return DYNAMIC_BOOTP_LEASE_CUTOFF; + if (!strcasecmp (atom + 13, "-lease-length")) + return DYNAMIC_BOOTP_LEASE_LENGTH; + break; + } + break; + case 'e': + if (!strcasecmp (atom + 1, "thernet")) + return ETHERNET; + if (!strcasecmp (atom + 1, "nds")) + return ENDS; + if (!strcasecmp (atom + 1, "xpire")) + return EXPIRE; + break; + case 'f': + if (!strcasecmp (atom + 1, "ilename")) + return FILENAME; + if (!strcasecmp (atom + 1, "ixed-address")) + return FIXED_ADDR; + break; + case 'g': + if (!strcasecmp (atom + 1, "iaddr")) + return GIADDR; + if (!strcasecmp (atom + 1, "roup")) + return GROUP; + if (!strcasecmp (atom + 1, "et-lease-hostnames")) + return GET_LEASE_HOSTNAMES; + break; + case 'h': + if (!strcasecmp (atom + 1, "ost")) + return HOST; + if (!strcasecmp (atom + 1, "ardware")) + return HARDWARE; + if (!strcasecmp (atom + 1, "ostname")) + return HOSTNAME; + break; + case 'i': + if (!strcasecmp (atom + 1, "nitial-interval")) + return INITIAL_INTERVAL; + if (!strcasecmp (atom + 1, "nterface")) + return INTERFACE; + break; + case 'l': + if (!strcasecmp (atom + 1, "ease")) + return LEASE; + break; + case 'm': + if (!strcasecmp (atom + 1, "ax-lease-time")) + return MAX_LEASE_TIME; + if (!strncasecmp (atom + 1, "edi", 3)) { + if (!strcasecmp (atom + 4, "a")) + return MEDIA; + if (!strcasecmp (atom + 4, "um")) + return MEDIUM; + break; + } + break; + case 'n': + if (!strcasecmp (atom + 1, "ameserver")) + return NAMESERVER; + if (!strcasecmp (atom + 1, "etmask")) + return NETMASK; + if (!strcasecmp (atom + 1, "ext-server")) + return NEXT_SERVER; + break; + case 'o': + if (!strcasecmp (atom + 1, "ption")) + return OPTION; + if (!strcasecmp (atom + 1, "ne-lease-per-client")) + return ONE_LEASE_PER_CLIENT; + break; + case 'p': + if (!strcasecmp (atom + 1, "repend")) + return PREPEND; + if (!strcasecmp (atom + 1, "acket")) + return PACKET; + break; + case 'r': + if (!strcasecmp (atom + 1, "ange")) + return RANGE; + if (!strcasecmp (atom + 1, "equest")) + return REQUEST; + if (!strcasecmp (atom + 1, "equire")) + return REQUIRE; + if (!strcasecmp (atom + 1, "etry")) + return RETRY; + if (!strcasecmp (atom + 1, "enew")) + return RENEW; + if (!strcasecmp (atom + 1, "ebind")) + return REBIND; + if (!strcasecmp (atom + 1, "eboot")) + return REBOOT; + if (!strcasecmp (atom + 1, "eject")) + return REJECT; + break; + case 's': + if (!strcasecmp (atom + 1, "earch")) + return SEARCH; + if (!strcasecmp (atom + 1, "tarts")) + return STARTS; + if (!strcasecmp (atom + 1, "iaddr")) + return SIADDR; + if (!strcasecmp (atom + 1, "ubnet")) + return SUBNET; + if (!strcasecmp (atom + 1, "hared-network")) + return SHARED_NETWORK; + if (!strcasecmp (atom + 1, "erver-name")) + return SERVER_NAME; + if (!strcasecmp (atom + 1, "erver-identifier")) + return SERVER_IDENTIFIER; + if (!strcasecmp (atom + 1, "elect-timeout")) + return SELECT_TIMEOUT; + if (!strcasecmp (atom + 1, "end")) + return SEND; + if (!strcasecmp (atom + 1, "cript")) + return SCRIPT; + if (!strcasecmp (atom + 1, "upersede")) + return SUPERSEDE; + break; + case 't': + if (!strcasecmp (atom + 1, "imestamp")) + return TIMESTAMP; + if (!strcasecmp (atom + 1, "imeout")) + return TIMEOUT; + if (!strcasecmp (atom + 1, "oken-ring")) + return TOKEN_RING; + break; + case 'u': + if (!strcasecmp (atom + 1, "id")) + return UID; + if (!strcasecmp (atom + 1, "ser-class")) + return USER_CLASS; + if (!strcasecmp (atom + 1, "se-host-decl-names")) + return USE_HOST_DECL_NAMES; + if (!strcasecmp (atom + 1, "nknown-clients")) + return UNKNOWN_CLIENTS; + break; + case 'v': + if (!strcasecmp (atom + 1, "endor-class")) + return VENDOR_CLASS; + break; + case 'y': + if (!strcasecmp (atom + 1, "iaddr")) + return YIADDR; + break; + } + return dfv; +} diff --git a/contrib/isc-dhcp/common/convert.c b/contrib/isc-dhcp/common/convert.c new file mode 100644 index 0000000..42f488b --- /dev/null +++ b/contrib/isc-dhcp/common/convert.c @@ -0,0 +1,118 @@ +/* convert.c + + Safe copying of option values into and out of the option buffer, which + can't be assumed to be aligned. */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: convert.c,v 1.4.2.1 1998/06/25 21:11:28 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +u_int32_t getULong (buf) + unsigned char *buf; +{ + unsigned long ibuf; + + memcpy (&ibuf, buf, sizeof (u_int32_t)); + return ntohl (ibuf); +} + +int32_t getLong (buf) + unsigned char *buf; +{ + long ibuf; + + memcpy (&ibuf, buf, sizeof (int32_t)); + return ntohl (ibuf); +} + +u_int16_t getUShort (buf) + unsigned char *buf; +{ + unsigned short ibuf; + + memcpy (&ibuf, buf, sizeof (u_int16_t)); + return ntohs (ibuf); +} + +int16_t getShort (buf) + unsigned char *buf; +{ + short ibuf; + + memcpy (&ibuf, buf, sizeof (int16_t)); + return ntohs (ibuf); +} + +void putULong (obuf, val) + unsigned char *obuf; + u_int32_t val; +{ + u_int32_t tmp = htonl (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putLong (obuf, val) + unsigned char *obuf; + int32_t val; +{ + int32_t tmp = htonl (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putUShort (obuf, val) + unsigned char *obuf; + unsigned int val; +{ + u_int16_t tmp = htons (val); + memcpy (obuf, &tmp, sizeof tmp); +} + +void putShort (obuf, val) + unsigned char *obuf; + int val; +{ + int16_t tmp = htons (val); + memcpy (obuf, &tmp, sizeof tmp); +} + diff --git a/contrib/isc-dhcp/common/dhcp-options.5 b/contrib/isc-dhcp/common/dhcp-options.5 new file mode 100644 index 0000000..eb90ed6 --- /dev/null +++ b/contrib/isc-dhcp/common/dhcp-options.5 @@ -0,0 +1,451 @@ +.\" dhcp-options.5 +.\" +.\" 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.isc.org/isc''. To learn more about Vixie +.\" Enterprises, see ``http://www.vix.com''. +.TH dhcpd-options 5 +.SH NAME +dhcp-options - Dynamic Host Configuration Protocol options +.SH DESCRIPTION +The Dynamic Host Configuration protocol allows the client to receive +.B options +from the DHCP server describing the network configuration and various +services that are available on the network. When configuring +.B dhcpd(8) +or +.B dhclient(8) , +options must often be declared. The syntax for declaring options, +and the names and formats of the options that can be declared, are +documented here. +.SH REFERENCE: OPTION STATEMENTS +.PP +DHCP \fIoption\fR statements always start with the \fIoption\fR +keyword, followed by an option name, followed by option data. The +option names and data formats are described below. It is not +necessary to exhaustively specify all DHCP options - only those +options which are needed by clients must be specified. +.PP +Option data comes in a variety of formats, as defined below: +.PP +The +.B ip-address +data type can be entered either as an explicit IP +address (e.g., 239.254.197.10) or as a domain name (e.g., +haagen.isc.org). When entering a domain name, be sure that that +domain name resolves to a single IP address. +.PP +The +.B int32 +data type specifies a signed 32-bit integer. The +.B uint32 +data type specifies an unsigned 32-bit integer. The +.B int16 +and +.B uint16 +data types specify signed and unsigned 16-bit integers. The +.B int8 +and +.B uint8 +data types specify signed and unsigned 8-bit integers. +Unsigned 8-bit integers are also sometimes referred to as octets. +.PP +The +.B string +data type specifies an NVT ASCII string, which must be +enclosed in double quotes - for example, to specify a domain-name +option, the syntax would be +.nf +.sp 1 + option domain-name "isc.org"; +.fi +.PP +The +.B flag +data type specifies a boolean value. Booleans can be either true or +false (or on or off, if that makes more sense to you). +.PP +The +.B data-string +data type specifies either an NVT ASCII string +enclosed in double quotes, or a series of octets specified in +hexadecimal, seperated by colons. For example: +.nf +.sp 1 + option client-identifier "CLIENT-FOO"; +or + option client-identifier 43:4c:49:45:54:2d:46:4f:4f; +.fi +.PP +The documentation for the various options mentioned below is taken +from the latest IETF draft document on DHCP options. Options which +are not listed by name may be defined by the name option-\fInnn\fR, +where \fInnn\fI is the decimal number of the option code. These +options may be followed either by a string, enclosed in quotes, or by +a series of octets, expressed as two-digit hexadecimal numbers seperated +by colons. For example: +.PP +.nf + option option-133 "my-option-133-text"; + option option-129 1:54:c9:2b:47; +.fi +.PP +Because dhcpd does not know the format of these undefined option codes, +no checking is done to ensure the correctness of the entered data. +.PP +The standard options are: +.PP + \fBoption subnet-mask\fR \fIip-address\fR\fB;\fR +.PP +The subnet mask option specifies the client's subnet mask as per RFC +950. If no subnet mask option is provided anywhere in scope, as a +last resort dhcpd will use the subnet mask from the subnet declaration +for the network on which an address is being assigned. However, +.I any +subnet-mask option declaration that is in scope for the address being +assigned will override the subnet mask specified in the subnet +declaration. +.PP + \fBoption time-offset\fR \fIint32\fR\fB;\fR +.PP +The time-offset option specifies the offset of the client's subnet in +seconds from Coordinated Universal Time (UTC). +.PP + \fBoption routers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The routers option specifies a list of IP addresses for routers on the +client's subnet. Routers should be listed in order of preference. +.PP + \fBoption time-servers\fR \fIip-address [, \fIip-address\fR ... ]\fB;\fR +.PP +The time-server option specifies a list of RFC 868 time servers +available to the client. Servers should be listed in order of +preference. +.PP + \fBoption\fR \fBien116-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]; +.PP +The ien116-name-servers option specifies a list of IEN 116 name servers +available to the client. Servers should be listed in order of +preference. +.PP + \fBoption\fR \fBdomain-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The domain-name-servers option specifies a list of Domain Name System +(STD 13, RFC 1035) name servers available to the client. Servers +should be listed in order of preference. +.PP + \fBoption\fR \fBlog-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The log-server option specifies a list of MIT-LCS UDP log servers +available to the client. Servers should be listed in order of +preference. +.PP + \fBoption\fR \fBcookie-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The cookie server option specifies a list of RFC 865 cookie +servers available to the client. Servers should be listed in order +of preference. +.PP + \fBoption\fR \fBlpr-servers\fR \fIip-address \fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The LPR server option specifies a list of RFC 1179 line printer +servers available to the client. Servers should be listed in order +of preference. +.PP + \fBoption\fR \fBimpress-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The impress-server option specifies a list of Imagen Impress servers +available to the client. Servers should be listed in order of +preference. +.PP + \fBoption\fR \fBresource-location-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of RFC 887 Resource Location +servers available to the client. Servers should be listed in order +of preference. +.PP + \fBoption\fR \fBhost-name\fR \fIstring\fR\fB;\fR +.PP +This option specifies the name of the client. The name may or may +not be qualified with the local domain name (it is preferable to use +the domain-name option to specify the domain name). See RFC 1035 for +character set restrictions. +.PP + \fBoption\fR \fBboot-size\fR \fIuint16\fR\fB;\fR +.PP +This option specifies the length in 512-octet blocks of the default +boot image for the client. +.PP + \fBoption\fR \fBmerit-dump\fR \fIstring\fR\fB;\fR +.PP +This option specifies the path-name of a file to which the client's +core image should be dumped in the event the client crashes. The +path is formatted as a character string consisting of characters from +the NVT ASCII character set. +.PP + \fBoption\fR \fBdomain-name\fR \fIstring\fR\fB;\fR +.PP +This option specifies the domain name that client should use when +resolving hostnames via the Domain Name System. +.PP + \fBoption\fR \fBswap-server\fR \fIip-address\fR\fB;\fR +.PP +This specifies the IP address of the client's swap server. +.PP + \fBoption\fR \fBroot-path\fR \fIstring\fB;\fR\fR +.PP +This option specifies the path-name that contains the client's root +disk. The path is formatted as a character string consisting of +characters from the NVT ASCII character set. +.PP + \fBoption\fR \fBip-forwarding\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether the client should configure its IP +layer for packet forwarding. A value of 0 means disable IP +forwarding, and a value of 1 means enable IP forwarding. +.PP + \fBoption\fR \fBnon-local-source-routing\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether the client should configure its IP +layer to allow forwarding of datagrams with non-local source routes +(see Section 3.3.5 of [4] for a discussion of this topic). A value +of 0 means disallow forwarding of such datagrams, and a value of 1 +means allow forwarding. +.PP + \fBoption\fR \fBpolicy-filter\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR ... ]\fB;\fR +.PP +This option specifies policy filters for non-local source routing. +The filters consist of a list of IP addresses and masks which specify +destination/mask pairs with which to filter incoming source routes. +.PP +Any source routed datagram whose next-hop address does not match one +of the filters should be discarded by the client. +.PP +See STD 3 (RFC1122) for further information. +.PP + \fBoption\fR \fBmax-dgram-reassembly\fR \fIuint16\fR\fB;\fR +.PP +This option specifies the maximum size datagram that the client +should be prepared to reassemble. The minimum value legal value is +576. +.PP + \fBoption\fR \fBdefault-ip-ttl\fR \fIuint8;\fR +.PP +This option specifies the default time-to-live that the client should +use on outgoing datagrams. +.PP + \fBoption\fR \fBpath-mtu-aging-timeout\fR \fIuint32\fR\fB;\fR +.PP +This option specifies the timeout (in seconds) to use when aging Path +MTU values discovered by the mechanism defined in RFC 1191. +.PP + \fBoption\fR \fBpath-mtu-plateau-table\fR \fIuint16\fR [\fB,\fR \fIuint16\fR ... ]\fB;\fR +.PP +This option specifies a table of MTU sizes to use when performing +Path MTU Discovery as defined in RFC 1191. The table is formatted as +a list of 16-bit unsigned integers, ordered from smallest to largest. +The minimum MTU value cannot be smaller than 68. +.PP + \fBoption\fR \fBinterface-mtu\fR \fIuint16\fR\fB;\fR +.PP +This option specifies the MTU to use on this interface. The minimum +legal value for the MTU is 68. +.PP + \fBoption\fR \fBall-subnets-local\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client may assume that all +subnets of the IP network to which the client is connected use the +same MTU as the subnet of that network to which the client is +directly connected. A value of 1 indicates that all subnets share +the same MTU. A value of 0 means that the client should assume that +some subnets of the directly connected network may have smaller MTUs. +.PP + \fBoption\fR \fBbroadcast-address\fR \fIip-address\fR\fB;\fR +.PP +This option specifies the broadcast address in use on the client's +subnet. Legal values for broadcast addresses are specified in +section 3.2.1.3 of STD 3 (RFC1122). +.PP + \fBoption\fR \fBperform-mask-discovery\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client should perform subnet +mask discovery using ICMP. A value of 0 indicates that the client +should not perform mask discovery. A value of 1 means that the +client should perform mask discovery. +.PP + \fBoption\fR \fBmask-supplier\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client should respond to +subnet mask requests using ICMP. A value of 0 indicates that the +client should not respond. A value of 1 means that the client should +respond. +.PP + \fBoption\fR \fBrouter-discovery\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client should solicit +routers using the Router Discovery mechanism defined in RFC 1256. +A value of 0 indicates that the client should not perform +router discovery. A value of 1 means that the client should perform +router discovery. +.PP + \fBoption\fR \fBrouter-solicitation-address\fR \fIip-address\fR\fB;\fR +.PP +This option specifies the address to which the client should transmit +router solicitation requests. +.PP + \fBoption\fR \fBstatic-routes\fR \fIip-address ip-address\fR [\fB,\fR \fIip-address ip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of static routes that the client should +install in its routing cache. If multiple routes to the same +destination are specified, they are listed in descending order of +priority. +.PP +The routes consist of a list of IP address pairs. The first address +is the destination address, and the second address is the router for +the destination. +.PP +The default route (0.0.0.0) is an illegal destination for a static +route. To specify the default route, use the +.B routers +option. +.PP + \fBoption\fR \fBtrailer-encapsulation\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client should negotiate the +use of trailers (RFC 893 [14]) when using the ARP protocol. A value +of 0 indicates that the client should not attempt to use trailers. A +value of 1 means that the client should attempt to use trailers. +.PP + \fBoption\fR \fBarp-cache-timeout\fR \fIuint32\fR\fB;\fR +.PP +This option specifies the timeout in seconds for ARP cache entries. +.PP + \fBoption\fR \fBieee802-3-encapsulation\fR \fIflag\fR\fB;\fR +.PP +This option specifies whether or not the client should use Ethernet +Version 2 (RFC 894) or IEEE 802.3 (RFC 1042) encapsulation if the +interface is an Ethernet. A value of 0 indicates that the client +should use RFC 894 encapsulation. A value of 1 means that the client +should use RFC 1042 encapsulation. +.PP + \fBoption\fR \fBdefault-tcp-ttl\fR \fIuint8\fR\fB;\fR +.PP +This option specifies the default TTL that the client should use when +sending TCP segments. The minimum value is 1. +.PP + \fBoption\fR \fBtcp-keepalive-interval\fR \fIuint32\fR\fB;\fR +.PP +This option specifies the interval (in seconds) that the client TCP +should wait before sending a keepalive message on a TCP connection. +The time is specified as a 32-bit unsigned integer. A value of zero +indicates that the client should not generate keepalive messages on +connections unless specifically requested by an application. +.PP + \fBoption\fR \fBtcp-keepalive-garbage\fR \fIflag\fR\fB;\fR +.PP +This option specifies the whether or not the client should send TCP +keepalive messages with a octet of garbage for compatibility with +older implementations. A value of 0 indicates that a garbage octet +should not be sent. A value of 1 indicates that a garbage octet +should be sent. +.PP + \fBoption\fR \fBnis-domain\fR \fIstring\fR\fB;\fR +.PP +This option specifies the name of the client's NIS (Sun Network +Information Services) domain. The domain is formatted as a character +string consisting of characters from the NVT ASCII character set. +.PP + \fBoption\fR \fBnis-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of IP addresses indicating NIS servers +available to the client. Servers should be listed in order of +preference. +.PP + \fBoption\fR \fBntp-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of IP addresses indicating NTP (RFC 1035) +servers available to the client. Servers should be listed in order +of preference. +.PP + \fBoption\fR \fBnetbios-name-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The NetBIOS name server (NBNS) option specifies a list of RFC +1001/1002 NBNS name servers listed in order of preference. +.PP + \fBoption\fR \fBnetbios-dd-server\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +The NetBIOS datagram distribution server (NBDD) option specifies a +list of RFC 1001/1002 NBDD servers listed in order of preference. +.PP + \fBoption\fR \fBnetbios-node-type\fR \fIuint8\fR\fB;\fR +.PP +The NetBIOS node type option allows NetBIOS over TCP/IP clients which +are configurable to be configured as described in RFC 1001/1002. The +value is specified as a single octet which identifies the client type. +A value of 1 corresponds to a NetBIOS B-node; a value of 2 corresponds +to a P-node; a value of 4 corresponds to an M-node; a value of 8 +corresponds to an H-node. +.PP + \fBoption\fR \fBnetbios-scope\fR \fIstring\fR\fB;\fR +.PP +The NetBIOS scope option specifies the NetBIOS over TCP/IP scope +parameter for the client as specified in RFC 1001/1002. See RFC1001, +RFC1002, and RFC1035 for character-set restrictions. +.PP + \fBoption\fR \fBfont-servers\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of X Window System Font servers available +to the client. Servers should be listed in order of preference. +.PP + \fBoption\fR \fBx-display-manager\fR \fIip-address\fR [\fB,\fR \fIip-address\fR ... ]\fB;\fR +.PP +This option specifies a list of systems that are running the X Window +System Display Manager and are available to the client. Addresses +should be listed in order of preference. +.PP + \fBoption\fR \fBdhcp-client-identifier\fR \fIdata-string\fR\fB;\fR +.PP +This option can be used to specify the a DHCP client identifier in a +host declaration, so that dhcpd can find the host record by matching +against the client identifier. +.SH SEE ALSO +dhcpd.conf(5), dhcpd.leases(5), dhclient.conf(5), dhcpd(8), +dhclient(8), RFC2132, RFC2131. +.SH AUTHOR +.B dhcpd(8) +was written by Ted Lemon <mellon@vix.com> +under a contract with Vixie Labs. Funding +for this project was provided by the Internet Software Corporation. +Information about the Internet Software Consortium can be found at +.B http://www.isc.org/isc. diff --git a/contrib/isc-dhcp/common/dispatch.c b/contrib/isc-dhcp/common/dispatch.c new file mode 100644 index 0000000..92fd579 --- /dev/null +++ b/contrib/isc-dhcp/common/dispatch.c @@ -0,0 +1,750 @@ +/* dispatch.c + + Network input dispatcher... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: dispatch.c,v 1.47.2.2 1998/06/25 21:11:28 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include <sys/ioctl.h> + +struct interface_info *interfaces, *dummy_interfaces; +struct protocol *protocols; +struct timeout *timeouts; +static struct timeout *free_timeouts; +static int interfaces_invalidated; +void (*bootp_packet_handler) PROTO ((struct interface_info *, + struct dhcp_packet *, int, unsigned int, + struct iaddr, struct hardware *)); + +static void got_one PROTO ((struct protocol *)); +int quiet_interface_discovery; + +/* Use the SIOCGIFCONF ioctl to get a list of all the attached interfaces. + For each interface that's of type INET and not the loopback interface, + register that interface with the network I/O software, figure out what + subnet it's on, and add it to the list of interfaces. */ + +void discover_interfaces (state) + int state; +{ + struct interface_info *tmp; + struct interface_info *last, *next; + char buf [8192]; + struct ifconf ic; + struct ifreq ifr; + int i; + int sock; + int address_count = 0; + struct subnet *subnet; + struct shared_network *share; + struct sockaddr_in foo; + int ir; +#ifdef ALIAS_NAMES_PERMUTED + char *s; +#endif +#ifdef USE_FALLBACK + static struct shared_network fallback_network; +#endif + + /* Create an unbound datagram socket to do the SIOCGIFADDR ioctl on. */ + if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + error ("Can't create addrlist socket"); + + /* Get the interface configuration information... */ + ic.ifc_len = sizeof buf; + ic.ifc_ifcu.ifcu_buf = (caddr_t)buf; + i = ioctl(sock, SIOCGIFCONF, &ic); + + if (i < 0) + error ("ioctl: SIOCGIFCONF: %m"); + + /* If we already have a list of interfaces, and we're running as + a DHCP server, the interfaces were requested. */ + if (interfaces && (state == DISCOVER_SERVER || + state == DISCOVER_RELAY || + state == DISCOVER_REQUESTED)) + ir = 0; + else if (state == DISCOVER_UNCONFIGURED) + ir = INTERFACE_REQUESTED | INTERFACE_AUTOMATIC; + else + ir = INTERFACE_REQUESTED; + + /* Cycle through the list of interfaces looking for IP addresses. + Go through twice; once to count the number of addresses, and a + second time to copy them into an array of addresses. */ + for (i = 0; i < ic.ifc_len;) { + struct ifreq *ifp = (struct ifreq *)((caddr_t)ic.ifc_req + i); +#ifdef HAVE_SA_LEN + if (ifp -> ifr_addr.sa_len) + i += (sizeof ifp -> ifr_name) + ifp -> ifr_addr.sa_len; + else +#endif + i += sizeof *ifp; + +#ifdef ALIAS_NAMES_PERMUTED + if ((s = strrchr (ifp -> ifr_name, ':'))) { + *s = 0; + } +#endif + +#ifdef SKIP_DUMMY_INTERFACES + if (!strncmp (ifp -> ifr_name, "dummy", 5)) + continue; +#endif + + + /* See if this is the sort of interface we want to + deal with. */ + strcpy (ifr.ifr_name, ifp -> ifr_name); + if (ioctl (sock, SIOCGIFFLAGS, &ifr) < 0) + error ("Can't get interface flags for %s: %m", + ifr.ifr_name); + + /* Skip loopback, point-to-point and down interfaces, + except don't skip down interfaces if we're trying to + get a list of configurable interfaces. */ + if ((ifr.ifr_flags & IFF_LOOPBACK) || +#ifdef IFF_POINTOPOINT + (ifr.ifr_flags & IFF_POINTOPOINT) || +#endif + (!(ifr.ifr_flags & IFF_UP) && + state != DISCOVER_UNCONFIGURED)) + continue; + + /* See if we've seen an interface that matches this one. */ + for (tmp = interfaces; tmp; tmp = tmp -> next) + if (!strcmp (tmp -> name, ifp -> ifr_name)) + break; + + /* If there isn't already an interface by this name, + allocate one. */ + if (!tmp) { + tmp = ((struct interface_info *) + dmalloc (sizeof *tmp, "discover_interfaces")); + if (!tmp) + error ("Insufficient memory to %s %s", + "record interface", ifp -> ifr_name); + strcpy (tmp -> name, ifp -> ifr_name); + tmp -> next = interfaces; + tmp -> flags = ir; + interfaces = tmp; + } + + /* If we have the capability, extract link information + and record it in a linked list. */ +#ifdef AF_LINK + if (ifp -> ifr_addr.sa_family == AF_LINK) { + struct sockaddr_dl *foo = ((struct sockaddr_dl *) + (&ifp -> ifr_addr)); + tmp -> hw_address.hlen = foo -> sdl_alen; + tmp -> hw_address.htype = HTYPE_ETHER; /* XXX */ + memcpy (tmp -> hw_address.haddr, + LLADDR (foo), foo -> sdl_alen); + } else +#endif /* AF_LINK */ + + if (ifp -> ifr_addr.sa_family == AF_INET) { + struct iaddr addr; + +#if defined (SIOCGIFHWADDR) && !defined (AF_LINK) + struct ifreq ifr; + struct sockaddr sa; + int b, sk; + + /* Read the hardware address from this interface. */ + ifr = *ifp; + if (ioctl (sock, SIOCGIFHWADDR, &ifr) < 0) + error ("Can't get hardware address for %s: %m", + ifr.ifr_name); + + sa = *(struct sockaddr *)&ifr.ifr_hwaddr; + + switch (sa.sa_family) { +#ifdef ARPHRD_LOOPBACK + case ARPHRD_LOOPBACK: + /* ignore loopback interface */ + break; +#endif + + case ARPHRD_ETHER: + tmp -> hw_address.hlen = 6; + tmp -> hw_address.htype = ARPHRD_ETHER; + memcpy (tmp -> hw_address.haddr, + sa.sa_data, 6); + break; + +#ifndef ARPHRD_IEEE802 +# define ARPHRD_IEEE802 HTYPE_IEEE802 +#endif + case ARPHRD_IEEE802: + tmp -> hw_address.hlen = 6; + tmp -> hw_address.htype = ARPHRD_IEEE802; + memcpy (tmp -> hw_address.haddr, + sa.sa_data, 6); + break; + +#ifdef ARPHRD_METRICOM + case ARPHRD_METRICOM: + tmp -> hw_address.hlen = 6; + tmp -> hw_address.htype = ARPHRD_METRICOM; + memcpy (tmp -> hw_address.haddr, + sa.sa_data, 6); + + break; +#endif + + default: + error ("%s: unknown hardware address type %d", + ifr.ifr_name, sa.sa_family); + } +#endif /* defined (SIOCGIFHWADDR) && !defined (AF_LINK) */ + + /* Get a pointer to the address... */ + memcpy (&foo, &ifp -> ifr_addr, + sizeof ifp -> ifr_addr); + + /* We don't want the loopback interface. */ + if (foo.sin_addr.s_addr == htonl (INADDR_LOOPBACK)) + continue; + + + /* If this is the first real IP address we've + found, keep a pointer to ifreq structure in + which we found it. */ + if (!tmp -> ifp) { + struct ifreq *tif; +#ifdef HAVE_SA_LEN + int len = ((sizeof ifp -> ifr_name) + + ifp -> ifr_addr.sa_len); +#else + int len = sizeof *ifp; +#endif + tif = (struct ifreq *)malloc (len); + if (!tif) + error ("no space to remember ifp."); + memcpy (tif, ifp, len); + tmp -> ifp = tif; + tmp -> primary_address = foo.sin_addr; + } + + /* Grab the address... */ + addr.len = 4; + memcpy (addr.iabuf, &foo.sin_addr.s_addr, + addr.len); + + /* If there's a registered subnet for this address, + connect it together... */ + if ((subnet = find_subnet (addr))) { + /* If this interface has multiple aliases + on the same subnet, ignore all but the + first we encounter. */ + if (!subnet -> interface) { + subnet -> interface = tmp; + subnet -> interface_address = addr; + } else if (subnet -> interface != tmp) { + warn ("Multiple %s %s: %s %s", + "interfaces match the", + "same subnet", + subnet -> interface -> name, + tmp -> name); + } + share = subnet -> shared_network; + if (tmp -> shared_network && + tmp -> shared_network != share) { + warn ("Interface %s matches %s", + tmp -> name, + "multiple shared networks"); + } else { + tmp -> shared_network = share; + } + + if (!share -> interface) { + share -> interface = tmp; + } else if (share -> interface != tmp) { + warn ("Multiple %s %s: %s %s", + "interfaces match the", + "same shared network", + share -> interface -> name, + tmp -> name); + } + } + } + } + + /* If we're just trying to get a list of interfaces that we might + be able to configure, we can quit now. */ + if (state == DISCOVER_UNCONFIGURED) + return; + + /* Weed out the interfaces that did not have IP addresses. */ + last = (struct interface_info *)0; + for (tmp = interfaces; tmp; tmp = next) { + next = tmp -> next; + if ((tmp -> flags & INTERFACE_AUTOMATIC) && + state == DISCOVER_REQUESTED) + tmp -> flags &= ~(INTERFACE_AUTOMATIC | + INTERFACE_REQUESTED); + if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) { + if ((tmp -> flags & INTERFACE_REQUESTED) != ir) + error ("%s: not found", tmp -> name); + if (!last) + interfaces = interfaces -> next; + else + last -> next = tmp -> next; + + /* Remember the interface in case we need to know + about it later. */ + tmp -> next = dummy_interfaces; + dummy_interfaces = tmp; + continue; + } + last = tmp; + + memcpy (&foo, &tmp -> ifp -> ifr_addr, + sizeof tmp -> ifp -> ifr_addr); + + /* We must have a subnet declaration for each interface. */ + if (!tmp -> shared_network && (state == DISCOVER_SERVER)) + error ("No subnet declaration for %s (%s).", + tmp -> name, inet_ntoa (foo.sin_addr)); + + /* Find subnets that don't have valid interface + addresses... */ + for (subnet = (tmp -> shared_network + ? tmp -> shared_network -> subnets + : (struct subnet *)0); + subnet; subnet = subnet -> next_sibling) { + if (!subnet -> interface_address.len) { + /* Set the interface address for this subnet + to the first address we found. */ + subnet -> interface_address.len = 4; + memcpy (subnet -> interface_address.iabuf, + &foo.sin_addr.s_addr, 4); + } + } + + /* Register the interface... */ + if_register_receive (tmp); + if_register_send (tmp); + } + + /* Now register all the remaining interfaces as protocols. */ + for (tmp = interfaces; tmp; tmp = tmp -> next) + add_protocol (tmp -> name, tmp -> rfdesc, got_one, tmp); + + close (sock); + +#ifdef USE_FALLBACK + strcpy (fallback_interface.name, "fallback"); + fallback_interface.shared_network = &fallback_network; + fallback_network.name = "fallback-net"; + if_register_fallback (&fallback_interface); + add_protocol ("fallback", fallback_interface.wfdesc, + fallback_discard, &fallback_interface); +#endif +} + +void reinitialize_interfaces () +{ + struct interface_info *ip; + + for (ip = interfaces; ip; ip = ip -> next) { + if_reinitialize_receive (ip); + if_reinitialize_send (ip); + } + +#ifdef USE_FALLBACK + if_reinitialize_fallback (&fallback_interface); +#endif + + interfaces_invalidated = 1; +} + +#ifdef USE_POLL +/* Wait for packets to come in using poll(). Anyway, when a packet + comes in, call receive_packet to receive the packet and possibly + strip hardware addressing information from it, and then call + do_packet to try to do something with it. + + As you can see by comparing this with the code that uses select(), + below, this is gratuitously complex. Quelle surprise, eh? This is + SysV we're talking about, after all, and even in the 90's, it + wouldn't do for SysV to make networking *easy*, would it? Rant, + rant... */ + +void dispatch () +{ + struct protocol *l; + int nfds = 0; + struct pollfd *fds; + int count; + int i; + int to_msec; + + nfds = 0; + for (l = protocols; l; l = l -> next) { + ++nfds; + } + fds = (struct pollfd *)malloc ((nfds) * sizeof (struct pollfd)); + if (!fds) + error ("Can't allocate poll structures."); + + do { + /* Call any expired timeouts, and then if there's + still a timeout registered, time out the select + call then. */ + another: + if (timeouts) { + struct timeout *t; + if (timeouts -> when <= cur_time) { + t = timeouts; + timeouts = timeouts -> next; + (*(t -> func)) (t -> what); + t -> next = free_timeouts; + free_timeouts = t; + goto another; + } + /* Figure timeout in milliseconds, and check for + potential overflow. We assume that integers + are 32 bits, which is harmless if they're 64 + bits - we'll just get extra timeouts in that + case. Lease times would have to be quite + long in order for a 32-bit integer to overflow, + anyway. */ + to_msec = timeouts -> when - cur_time; + if (to_msec > 2147483) + to_msec = 2147483; + to_msec *= 1000; + } else + to_msec = -1; + + /* Set up the descriptors to be polled. */ + i = 0; + for (l = protocols; l; l = l -> next) { + fds [i].fd = l -> fd; + fds [i].events = POLLIN; + fds [i].revents = 0; + ++i; + } + + /* Wait for a packet or a timeout... XXX */ + count = poll (fds, nfds, to_msec); + + /* Get the current time... */ + GET_TIME (&cur_time); + + /* Not likely to be transitory... */ + if (count < 0) { + if (errno == EAGAIN || errno == EINTR) + continue; + else + error ("poll: %m"); + } + + i = 0; + for (l = protocols; l; l = l -> next) { + if ((fds [i].revents & POLLIN)) { + fds [i].revents = 0; + if (l -> handler) + (*(l -> handler)) (l); + if (interfaces_invalidated) + break; + } + ++i; + } + interfaces_invalidated = 0; + } while (1); +} +#else +/* Wait for packets to come in using select(). When one does, call + receive_packet to receive the packet and possibly strip hardware + addressing information from it, and then call do_packet to try to + do something with it. */ + +void dispatch () +{ + fd_set r, w, x; + struct protocol *l; + int max = 0; + int count; + struct timeval tv, *tvp; + + FD_ZERO (&w); + FD_ZERO (&x); + + do { + /* Call any expired timeouts, and then if there's + still a timeout registered, time out the select + call then. */ + another: + if (timeouts) { + struct timeout *t; + if (timeouts -> when <= cur_time) { + t = timeouts; + timeouts = timeouts -> next; + (*(t -> func)) (t -> what); + t -> next = free_timeouts; + free_timeouts = t; + goto another; + } + tv.tv_sec = timeouts -> when - cur_time; + tv.tv_usec = 0; + tvp = &tv; + } else + tvp = (struct timeval *)0; + + /* Set up the read mask. */ + FD_ZERO (&r); + + for (l = protocols; l; l = l -> next) { + FD_SET (l -> fd, &r); + if (l -> fd > max) + max = l -> fd; + } + + /* Wait for a packet or a timeout... XXX */ + count = select (max + 1, &r, &w, &x, tvp); + + /* Get the current time... */ + GET_TIME (&cur_time); + + /* Not likely to be transitory... */ + if (count < 0) + error ("select: %m"); + + for (l = protocols; l; l = l -> next) { + if (!FD_ISSET (l -> fd, &r)) + continue; + if (l -> handler) + (*(l -> handler)) (l); + if (interfaces_invalidated) + break; + } + interfaces_invalidated = 0; + } while (1); +} +#endif /* USE_POLL */ + +static void got_one (l) + struct protocol *l; +{ + struct sockaddr_in from; + struct hardware hfrom; + struct iaddr ifrom; + int result; + union { + unsigned char packbuf [4095]; /* Packet input buffer. + Must be as large as largest + possible MTU. */ + struct dhcp_packet packet; + } u; + struct interface_info *ip = l -> local; + + if ((result = + receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) { + warn ("receive_packet failed on %s: %m", ip -> name); + return; + } + if (result == 0) + return; + + if (bootp_packet_handler) { + ifrom.len = 4; + memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len); + + (*bootp_packet_handler) (ip, &u.packet, result, + from.sin_port, ifrom, &hfrom); + } +} + +int locate_network (packet) + struct packet *packet; +{ + struct iaddr ia; + + /* If this came through a gateway, find the corresponding subnet... */ + if (packet -> raw -> giaddr.s_addr) { + struct subnet *subnet; + ia.len = 4; + memcpy (ia.iabuf, &packet -> raw -> giaddr, 4); + subnet = find_subnet (ia); + if (subnet) + packet -> shared_network = subnet -> shared_network; + else + packet -> shared_network = (struct shared_network *)0; + } else { + packet -> shared_network = + packet -> interface -> shared_network; + } + if (packet -> shared_network) + return 1; + return 0; +} + +void add_timeout (when, where, what) + TIME when; + void (*where) PROTO ((void *)); + void *what; +{ + struct timeout *t, *q; + + /* See if this timeout supersedes an existing timeout. */ + t = (struct timeout *)0; + for (q = timeouts; q; q = q -> next) { + if (q -> func == where && q -> what == what) { + if (t) + t -> next = q -> next; + else + timeouts = q -> next; + break; + } + t = q; + } + + /* If we didn't supersede a timeout, allocate a timeout + structure now. */ + if (!q) { + if (free_timeouts) { + q = free_timeouts; + free_timeouts = q -> next; + q -> func = where; + q -> what = what; + } else { + q = (struct timeout *)malloc (sizeof (struct timeout)); + if (!q) + error ("Can't allocate timeout structure!"); + q -> func = where; + q -> what = what; + } + } + + q -> when = when; + + /* Now sort this timeout into the timeout list. */ + + /* Beginning of list? */ + if (!timeouts || timeouts -> when > q -> when) { + q -> next = timeouts; + timeouts = q; + return; + } + + /* Middle of list? */ + for (t = timeouts; t -> next; t = t -> next) { + if (t -> next -> when > q -> when) { + q -> next = t -> next; + t -> next = q; + return; + } + } + + /* End of list. */ + t -> next = q; + q -> next = (struct timeout *)0; +} + +void cancel_timeout (where, what) + void (*where) PROTO ((void *)); + void *what; +{ + struct timeout *t, *q; + + /* Look for this timeout on the list, and unlink it if we find it. */ + t = (struct timeout *)0; + for (q = timeouts; q; q = q -> next) { + if (q -> func == where && q -> what == what) { + if (t) + t -> next = q -> next; + else + timeouts = q -> next; + break; + } + t = q; + } + + /* If we found the timeout, put it on the free list. */ + if (q) { + q -> next = free_timeouts; + free_timeouts = q; + } +} + +/* Add a protocol to the list of protocols... */ +void add_protocol (name, fd, handler, local) + char *name; + int fd; + void (*handler) PROTO ((struct protocol *)); + void *local; +{ + struct protocol *p; + + p = (struct protocol *)malloc (sizeof *p); + if (!p) + error ("can't allocate protocol struct for %s", name); + + p -> fd = fd; + p -> handler = handler; + p -> local = local; + + p -> next = protocols; + protocols = p; +} + +void remove_protocol (proto) + struct protocol *proto; +{ + struct protocol *p, *next, *prev; + + prev = (struct protocol *)0; + for (p = protocols; p; p = next) { + next = p -> next; + if (p == proto) { + if (prev) + prev -> next = p -> next; + else + protocols = p -> next; + free (p); + } + } +} diff --git a/contrib/isc-dhcp/common/errwarn.c b/contrib/isc-dhcp/common/errwarn.c new file mode 100644 index 0000000..078ae41 --- /dev/null +++ b/contrib/isc-dhcp/common/errwarn.c @@ -0,0 +1,391 @@ +/* errwarn.c + + Errors and warnings... */ + +/* + * Copyright (c) 1996 The Internet Software Consortium. + * All Rights Reserved. + * Copyright (c) 1995 RadioMail Corporation. 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 RadioMail Corporation, 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 RADIOMAIL CORPORATION, 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 RADIOMAIL CORPORATION 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 was written for RadioMail Corporation by Ted Lemon + * under a contract with Vixie Enterprises. Further modifications have + * been made for the Internet Software Consortium under a contract + * with Vixie Laboratories. + */ + +#ifndef lint +static char copyright[] = +"$Id: errwarn.c,v 1.15 1997/05/09 08:03:44 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include <errno.h> + +static void do_percentm PROTO ((char *obuf, char *ibuf)); + +static char mbuf [1024]; +static char fbuf [1024]; + +int warnings_occurred; + +/* Log an error message, then exit... */ + +void error (ANSI_DECL(char *) fmt, VA_DOTDOTDOT) + KandR (char *fmt;) + va_dcl +{ + va_list list; + extern int logged_in; + + do_percentm (fbuf, fmt); + + VA_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, mbuf); +#endif + + /* Also log it to stderr? */ + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + syslog (LOG_CRIT, "exiting."); + if (log_perror) { + fprintf (stderr, "exiting.\n"); + fflush (stderr); + } + cleanup (); + exit (1); +} + +/* Log a warning message... */ + +int warn (ANSI_DECL (char *) fmt, VA_DOTDOTDOT) + KandR (char *fmt;) + va_dcl +{ + va_list list; + + do_percentm (fbuf, fmt); + + VA_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Log a note... */ + +int note (ANSI_DECL (char *) fmt, VA_DOTDOTDOT) + KandR (char *fmt;) + va_dcl +{ + va_list list; + + do_percentm (fbuf, fmt); + + VA_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_INFO, mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Log a debug message... */ + +int debug (ANSI_DECL (char *) fmt, VA_DOTDOTDOT) + KandR (char *fmt;) + va_dcl +{ + va_list list; + + do_percentm (fbuf, fmt); + + VA_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_DEBUG, mbuf); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + } + + return 0; +} + +/* Find %m in the input string and substitute an error message string. */ + +static void do_percentm (obuf, ibuf) + char *obuf; + char *ibuf; +{ + char *s = ibuf; + char *p = obuf; + int infmt = 0; + char *m; + + while (*s) + { + if (infmt) + { + if (*s == 'm') + { +#ifndef __CYGWIN32__ + m = strerror (errno); +#else + m = pWSAError (); +#endif + if (!m) + m = "<unknown error>"; + strcpy (p - 1, m); + p += strlen (p); + ++s; + } + else + *p++ = *s++; + infmt = 0; + } + else + { + if (*s == '%') + infmt = 1; + *p++ = *s++; + } + } + *p = 0; +} + + +int parse_warn (ANSI_DECL (char *) fmt, VA_DOTDOTDOT) + KandR (char *fmt;) + va_dcl +{ + va_list list; + static char spaces [] = " "; + + do_percentm (mbuf, fmt); +#ifndef NO_SNPRINTF + snprintf (fbuf, sizeof fbuf, "%s line %d: %s", + tlname, lexline, mbuf); +#else + sprintf (fbuf, "%s line %d: %s", + tlname, lexline, mbuf); +#endif + + VA_start (list, fmt); + vsnprintf (mbuf, sizeof mbuf, fbuf, list); + va_end (list); + +#ifndef DEBUG + syslog (log_priority | LOG_ERR, mbuf); + syslog (log_priority | LOG_ERR, token_line); + if (lexline < 81) + syslog (log_priority | LOG_ERR, + "%s^", &spaces [sizeof spaces - lexchar]); +#endif + + if (log_perror) { + write (2, mbuf, strlen (mbuf)); + write (2, "\n", 1); + write (2, token_line, strlen (token_line)); + write (2, "\n", 1); + write (2, spaces, lexchar - 1); + write (2, "^\n", 2); + } + + warnings_occurred = 1; + + return 0; +} + +#ifdef NO_STRERROR +char *strerror (err) + int err; +{ + extern char *sys_errlist []; + extern int sys_nerr; + static char errbuf [128]; + + if (err < 0 || err >= sys_nerr) { + sprintf (errbuf, "Error %d", err); + return errbuf; + } + return sys_errlist [err]; +} +#endif /* NO_STRERROR */ + +#ifdef _WIN32 +char *pWSAError () +{ + int err = WSAGetLastError (); + + switch (err) + { + case WSAEACCES: + return "Permission denied"; + case WSAEADDRINUSE: + return "Address already in use"; + case WSAEADDRNOTAVAIL: + return "Cannot assign requested address"; + case WSAEAFNOSUPPORT: + return "Address family not supported by protocol family"; + case WSAEALREADY: + return "Operation already in progress"; + case WSAECONNABORTED: + return "Software caused connection abort"; + case WSAECONNREFUSED: + return "Connection refused"; + case WSAECONNRESET: + return "Connection reset by peer"; + case WSAEDESTADDRREQ: + return "Destination address required"; + case WSAEFAULT: + return "Bad address"; + case WSAEHOSTDOWN: + return "Host is down"; + case WSAEHOSTUNREACH: + return "No route to host"; + case WSAEINPROGRESS: + return "Operation now in progress"; + case WSAEINTR: + return "Interrupted function call"; + case WSAEINVAL: + return "Invalid argument"; + case WSAEISCONN: + return "Socket is already connected"; + case WSAEMFILE: + return "Too many open files"; + case WSAEMSGSIZE: + return "Message too long"; + case WSAENETDOWN: + return "Network is down"; + case WSAENETRESET: + return "Network dropped connection on reset"; + case WSAENETUNREACH: + return "Network is unreachable"; + case WSAENOBUFS: + return "No buffer space available"; + case WSAENOPROTOOPT: + return "Bad protocol option"; + case WSAENOTCONN: + return "Socket is not connected"; + case WSAENOTSOCK: + return "Socket operation on non-socket"; + case WSAEOPNOTSUPP: + return "Operation not supported"; + case WSAEPFNOSUPPORT: + return "Protocol family not supported"; + case WSAEPROCLIM: + return "Too many processes"; + case WSAEPROTONOSUPPORT: + return "Protocol not supported"; + case WSAEPROTOTYPE: + return "Protocol wrong type for socket"; + case WSAESHUTDOWN: + return "Cannot send after socket shutdown"; + case WSAESOCKTNOSUPPORT: + return "Socket type not supported"; + case WSAETIMEDOUT: + return "Connection timed out"; + case WSAEWOULDBLOCK: + return "Resource temporarily unavailable"; + case WSAHOST_NOT_FOUND: + return "Host not found"; +#if 0 + case WSA_INVALID_HANDLE: + return "Specified event object handle is invalid"; + case WSA_INVALID_PARAMETER: + return "One or more parameters are invalid"; + case WSAINVALIDPROCTABLE: + return "Invalid procedure table from service provider"; + case WSAINVALIDPROVIDER: + return "Invalid service provider version number"; + case WSA_IO_PENDING: + return "Overlapped operations will complete later"; + case WSA_IO_INCOMPLETE: + return "Overlapped I/O event object not in signaled state"; + case WSA_NOT_ENOUGH_MEMORY: + return "Insufficient memory available"; +#endif + case WSANOTINITIALISED: + return "Successful WSAStartup not yet performer"; + case WSANO_DATA: + return "Valid name, no data record of requested type"; + case WSANO_RECOVERY: + return "This is a non-recoverable error"; +#if 0 + case WSAPROVIDERFAILEDINIT: + return "Unable to initialize a service provider"; + case WSASYSCALLFAILURE: + return "System call failure"; +#endif + case WSASYSNOTREADY: + return "Network subsystem is unavailable"; + case WSATRY_AGAIN: + return "Non-authoritative host not found"; + case WSAVERNOTSUPPORTED: + return "WINSOCK.DLL version out of range"; + case WSAEDISCON: + return "Graceful shutdown in progress"; +#if 0 + case WSA_OPERATION_ABORTED: + return "Overlapped operation aborted"; +#endif + } + return "Unknown WinSock error"; +} +#endif /* _WIN32 */ diff --git a/contrib/isc-dhcp/common/hash.c b/contrib/isc-dhcp/common/hash.c new file mode 100644 index 0000000..8d362cb --- /dev/null +++ b/contrib/isc-dhcp/common/hash.c @@ -0,0 +1,175 @@ +/* hash.c + + Routines for manipulating hash tables... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: hash.c,v 1.9.2.1 1998/06/25 21:11:29 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +static INLINE int do_hash PROTO ((unsigned char *, int, int)); + +struct hash_table *new_hash () +{ + struct hash_table *rv = new_hash_table (DEFAULT_HASH_SIZE, "new_hash"); + if (!rv) + return rv; + memset (&rv -> buckets [0], 0, + DEFAULT_HASH_SIZE * sizeof (struct hash_bucket *)); + return rv; +} + +static INLINE int do_hash (name, len, size) + unsigned char *name; + int len; + int size; +{ + register int accum = 0; + register unsigned char *s = name; + int i = len; + if (i) { + while (i--) { + /* Add the character in... */ + accum += *s++; + /* Add carry back in... */ + while (accum > 255) { + accum = (accum & 255) + (accum >> 8); + } + } + } else { + while (*s) { + /* Add the character in... */ + accum += *s++; + /* Add carry back in... */ + while (accum > 255) { + accum = (accum & 255) + (accum >> 8); + } + } + } + return accum % size; +} + +void add_hash (table, name, len, pointer) + struct hash_table *table; + int len; + unsigned char *name; + unsigned char *pointer; +{ + int hashno; + struct hash_bucket *bp; + + if (!table) + return; + + hashno = do_hash (name, len, table -> hash_count); + bp = new_hash_bucket ("add_hash"); + + if (!bp) { + warn ("Can't add %s to hash table.", name); + return; + } + bp -> name = name; + bp -> value = pointer; + bp -> next = table -> buckets [hashno]; + bp -> len = len; + table -> buckets [hashno] = bp; +} + +void delete_hash_entry (table, name, len) + struct hash_table *table; + int len; + unsigned char *name; +{ + int hashno; + struct hash_bucket *bp, *pbp = (struct hash_bucket *)0; + + if (!table) + return; + + hashno = do_hash (name, len, table -> hash_count); + + /* Go through the list looking for an entry that matches; + if we find it, delete it. */ + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if ((!bp -> len && + !strcmp ((char *)bp -> name, (char *)name)) || + (bp -> len == len && + !memcmp (bp -> name, name, len))) { + if (pbp) { + pbp -> next = bp -> next; + } else { + table -> buckets [hashno] = bp -> next; + } + free_hash_bucket (bp, "delete_hash_entry"); + break; + } + pbp = bp; /* jwg, 9/6/96 - nice catch! */ + } +} + +unsigned char *hash_lookup (table, name, len) + struct hash_table *table; + unsigned char *name; + int len; +{ + int hashno; + struct hash_bucket *bp; + + if (!table) + return (unsigned char *)0; + hashno = do_hash (name, len, table -> hash_count); + + if (len) { + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) { + if (len == bp -> len + && !memcmp (bp -> name, name, len)) + return bp -> value; + } + } else { + for (bp = table -> buckets [hashno]; bp; bp = bp -> next) + if (!strcmp ((char *)bp -> name, (char *)name)) + return bp -> value; + } + return (unsigned char *)0; +} + diff --git a/contrib/isc-dhcp/common/icmp.c b/contrib/isc-dhcp/common/icmp.c new file mode 100644 index 0000000..fb6cfad --- /dev/null +++ b/contrib/isc-dhcp/common/icmp.c @@ -0,0 +1,177 @@ +/* icmp.c + + ICMP Protocol engine - for sending out pings and receiving + responses. */ + +/* + * Copyright (c) 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: icmp.c,v 1.7.2.1 1998/06/25 21:11:29 mellon Exp $ Copyright (c) 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include "netinet/ip.h" +#include "netinet/ip_icmp.h" + +static int icmp_protocol_initialized; +static int icmp_protocol_fd; + +/* Initialize the ICMP protocol. */ + +void icmp_startup (routep, handler) + int routep; + void (*handler) PROTO ((struct iaddr, u_int8_t *, int)); +{ + struct protoent *proto; + int protocol = 1; + struct sockaddr_in from; + int fd; + int state; + + /* Only initialize icmp once. */ + if (icmp_protocol_initialized) + error ("attempted to reinitialize icmp protocol"); + icmp_protocol_initialized = 1; + + /* Get the protocol number (should be 1). */ + proto = getprotobyname ("icmp"); + if (proto) + protocol = proto -> p_proto; + + /* Get a raw socket for the ICMP protocol. */ + icmp_protocol_fd = socket (AF_INET, SOCK_RAW, protocol); + if (icmp_protocol_fd < 0) + error ("unable to create icmp socket: %m"); + + /* Make sure it does routing... */ + state = 0; + if (setsockopt (icmp_protocol_fd, SOL_SOCKET, SO_DONTROUTE, + (char *)&state, sizeof state) < 0) + error ("Unable to disable SO_DONTROUTE on ICMP socket: %m"); + + add_protocol ("icmp", icmp_protocol_fd, icmp_echoreply, + (void *)handler); +} + +int icmp_echorequest (addr) + struct iaddr *addr; +{ + struct sockaddr_in to; + struct icmp icmp; + int status; + + if (!icmp_protocol_initialized) + error ("attempt to use ICMP protocol before initialization."); + +#ifdef HAVE_SA_LEN + to.sin_len = sizeof to; +#endif + to.sin_family = AF_INET; + to.sin_port = 0; /* unused. */ + memcpy (&to.sin_addr, addr -> iabuf, sizeof to.sin_addr); /* XXX */ + + icmp.icmp_type = ICMP_ECHO; + icmp.icmp_code = 0; + icmp.icmp_cksum = 0; + icmp.icmp_seq = 0; +#ifdef PTRSIZE_64BIT + icmp.icmp_id = (((u_int32_t)(u_int64_t)addr) ^ + (u_int32_t)(((u_int64_t)addr) >> 32)); +#else + icmp.icmp_id = (u_int32_t)addr; +#endif + + icmp.icmp_cksum = wrapsum (checksum ((unsigned char *)&icmp, + sizeof icmp, 0)); + + /* Send the ICMP packet... */ + status = sendto (icmp_protocol_fd, (char *)&icmp, sizeof icmp, 0, + (struct sockaddr *)&to, sizeof to); + if (status < 0) + warn ("icmp_echorequest %s: %m", inet_ntoa(to.sin_addr)); + + if (status != sizeof icmp) + return 0; + return 1; +} + +void icmp_echoreply (protocol) + struct protocol *protocol; +{ + struct icmp *icfrom; + struct sockaddr_in from; + u_int8_t icbuf [1500]; + int status; + int len; + struct iaddr ia; + void (*handler) PROTO ((struct iaddr, u_int8_t *, int)); + + len = sizeof from; + status = recvfrom (protocol -> fd, (char *)icbuf, sizeof icbuf, 0, + (struct sockaddr *)&from, &len); + if (status < 0) { + warn ("icmp_echoreply: %m"); + return; + } + + /* Probably not for us. */ + if (status < (sizeof (struct ip)) + (sizeof *icfrom)) { + return; + } + + len = status - sizeof (struct ip); + icfrom = (struct icmp *)(icbuf + sizeof (struct ip)); + + /* Silently discard ICMP packets that aren't echoreplies. */ + if (icfrom -> icmp_type != ICMP_ECHOREPLY) { + return; + } + + /* If we were given a second-stage handler, call it. */ + if (protocol -> local) { + handler = ((void (*) PROTO ((struct iaddr, + u_int8_t *, int))) + protocol -> local); + memcpy (ia.iabuf, &from.sin_addr, sizeof from.sin_addr); + ia.len = sizeof from.sin_addr; + + (*handler) (ia, icbuf, len); + } +} diff --git a/contrib/isc-dhcp/common/inet.c b/contrib/isc-dhcp/common/inet.c new file mode 100644 index 0000000..b7c4ba4 --- /dev/null +++ b/contrib/isc-dhcp/common/inet.c @@ -0,0 +1,178 @@ +/* inet.c + + Subroutines to manipulate internet addresses in a safely portable + way... */ + +/* + * Copyright (c) 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''. + */ + +#include "dhcpd.h" + +/* Return just the network number of an internet address... */ + +struct iaddr subnet_number (addr, mask) + struct iaddr addr; + struct iaddr mask; +{ + int i; + struct iaddr rv; + + rv.len = 0; + + /* Both addresses must have the same length... */ + if (addr.len != mask.len) + return rv; + + rv.len = addr.len; + for (i = 0; i < rv.len; i++) + rv.iabuf [i] = addr.iabuf [i] & mask.iabuf [i]; + return rv; +} + +/* Combine a network number and a integer to produce an internet address. + This won't work for subnets with more than 32 bits of host address, but + maybe this isn't a problem. */ + +struct iaddr ip_addr (subnet, mask, host_address) + struct iaddr subnet; + struct iaddr mask; + u_int32_t host_address; +{ + int i, j, k; + u_int32_t swaddr; + struct iaddr rv; + unsigned char habuf [sizeof swaddr]; + + swaddr = htonl (host_address); + memcpy (habuf, &swaddr, sizeof swaddr); + + /* Combine the subnet address and the host address. If + the host address is bigger than can fit in the subnet, + return a zero-length iaddr structure. */ + rv = subnet; + j = rv.len - sizeof habuf; + for (i = sizeof habuf - 1; i >= 0; i--) { + if (mask.iabuf [i + j]) { + if (habuf [i] > (mask.iabuf [i + j] ^ 0xFF)) { + rv.len = 0; + return rv; + } + for (k = i - 1; k >= 0; k--) { + if (habuf [k]) { + rv.len = 0; + return rv; + } + } + rv.iabuf [i + j] |= habuf [i]; + break; + } else + rv.iabuf [i + j] = habuf [i]; + } + + return rv; +} + +/* Given a subnet number and netmask, return the address on that subnet + for which the host portion of the address is all ones (the standard + broadcast address). */ + +struct iaddr broadcast_addr (subnet, mask) + struct iaddr subnet; + struct iaddr mask; +{ + int i, j, k; + struct iaddr rv; + + if (subnet.len != mask.len) { + rv.len = 0; + return rv; + } + + for (i = 0; i < subnet.len; i++) { + rv.iabuf [i] = subnet.iabuf [i] | (~mask.iabuf [i] & 255); + } + rv.len = subnet.len; + + return rv; +} + +u_int32_t host_addr (addr, mask) + struct iaddr addr; + struct iaddr mask; +{ + int i; + u_int32_t swaddr; + struct iaddr rv; + + rv.len = 0; + + /* Mask out the network bits... */ + rv.len = addr.len; + for (i = 0; i < rv.len; i++) + rv.iabuf [i] = addr.iabuf [i] & ~mask.iabuf [i]; + + /* Copy out up to 32 bits... */ + memcpy (&swaddr, &rv.iabuf [rv.len - sizeof swaddr], sizeof swaddr); + + /* Swap it and return it. */ + return ntohl (swaddr); +} + +int addr_eq (addr1, addr2) + struct iaddr addr1, addr2; +{ + if (addr1.len != addr2.len) + return 0; + return memcmp (addr1.iabuf, addr2.iabuf, addr1.len) == 0; +} + +char *piaddr (addr) + struct iaddr addr; +{ + static char pbuf [4 * 16]; + char *s = pbuf; + int i; + + if (addr.len == 0) { + strcpy (s, "<null address>"); + } + for (i = 0; i < addr.len; i++) { + sprintf (s, "%s%d", i ? "." : "", addr.iabuf [i]); + s += strlen (s); + } + return pbuf; +} diff --git a/contrib/isc-dhcp/common/inet_addr.c b/contrib/isc-dhcp/common/inet_addr.c new file mode 100644 index 0000000..b00a72c --- /dev/null +++ b/contrib/isc-dhcp/common/inet_addr.c @@ -0,0 +1,150 @@ +/* $NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $ */ + +/* + * Copyright (c) 1983, 1990, 1993 + * The Regents of the University of California. 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. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +#if 0 +static char sccsid[] = "@(#)inet_addr.c 8.1 (Berkeley) 6/17/93"; +#else +static char rcsid[] = "$NetBSD: inet_addr.c,v 1.6 1996/02/02 15:22:23 mrg Exp $"; +#endif +#endif /* LIBC_SCCS and not lint */ + +#ifndef lint +static char copyright[] = +"$Id: inet_addr.c,v 1.2.2.1 1998/06/26 20:51:35 mellon Exp $ Copyright (c) 1983, 1990, 1993 The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#ifdef NEED_INET_ATON +/* + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + */ +int +inet_aton(cp, addr) + const char *cp; + struct in_addr *addr; +{ + register u_long val; + register int base, n; + register char c; + u_int parts[4]; + register u_int *pp = parts; + + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, other=decimal. + */ + val = 0; base = 10; + if (*cp == '0') { + if (*++cp == 'x' || *cp == 'X') + base = 16, cp++; + else + base = 8; + } + while ((c = *cp) != '\0') { + if (isascii(c) && isdigit(c)) { + val = (val * base) + (c - '0'); + cp++; + continue; + } + if (base == 16 && isascii(c) && isxdigit(c)) { + val = (val << 4) + + (c + 10 - (islower(c) ? 'a' : 'A')); + cp++; + continue; + } + break; + } + if (*cp == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16-bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3 || val > 0xff) + return (0); + *pp++ = val, cp++; + } else + break; + } + /* + * Check for trailing characters. + */ + if (*cp && (!isascii(*cp) || !isspace(*cp))) + return (0); + /* + * Concoct the address according to + * the number of parts specified. + */ + n = pp - parts + 1; + switch (n) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffff) + return (0); + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) + return (0); + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + } + if (addr) + addr->s_addr = htonl(val); + return (1); +} +#endif diff --git a/contrib/isc-dhcp/common/memory.c b/contrib/isc-dhcp/common/memory.c new file mode 100644 index 0000000..59cbe5d --- /dev/null +++ b/contrib/isc-dhcp/common/memory.c @@ -0,0 +1,911 @@ +/* memory.c + + Memory-resident database... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: memory.c,v 1.35.2.2 1998/06/25 21:11:30 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +static struct subnet *subnets; +static struct shared_network *shared_networks; +static struct hash_table *host_hw_addr_hash; +static struct hash_table *host_uid_hash; +static struct hash_table *lease_uid_hash; +static struct hash_table *lease_ip_addr_hash; +static struct hash_table *lease_hw_addr_hash; +static struct lease *dangling_leases; + +static struct hash_table *vendor_class_hash; +static struct hash_table *user_class_hash; + +void enter_host (hd) + struct host_decl *hd; +{ + struct host_decl *hp = (struct host_decl *)0; + struct host_decl *np = (struct host_decl *)0; + + hd -> n_ipaddr = (struct host_decl *)0; + + if (hd -> interface.hlen) { + if (!host_hw_addr_hash) + host_hw_addr_hash = new_hash (); + else + hp = (struct host_decl *) + hash_lookup (host_hw_addr_hash, + hd -> interface.haddr, + hd -> interface.hlen); + + /* If there isn't already a host decl matching this + address, add it to the hash table. */ + if (!hp) + add_hash (host_hw_addr_hash, + hd -> interface.haddr, hd -> interface.hlen, + (unsigned char *)hd); + } + + /* If there was already a host declaration for this hardware + address, add this one to the end of the list. */ + + if (hp) { + for (np = hp; np -> n_ipaddr; np = np -> n_ipaddr) + ; + np -> n_ipaddr = hd; + } + + if (hd -> group -> options [DHO_DHCP_CLIENT_IDENTIFIER]) { + if (!tree_evaluate (hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER])) + return; + + /* If there's no uid hash, make one; otherwise, see if + there's already an entry in the hash for this host. */ + if (!host_uid_hash) { + host_uid_hash = new_hash (); + hp = (struct host_decl *)0; + } else + hp = (struct host_decl *) hash_lookup + (host_uid_hash, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> value, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> len); + + /* If there's already a host declaration for this + client identifier, add this one to the end of the + list. Otherwise, add it to the hash table. */ + if (hp) { + /* Don't link it in twice... */ + if (!np) { + for (np = hp; np -> n_ipaddr; + np = np -> n_ipaddr) + ; + np -> n_ipaddr = hd; + } + } else { + add_hash (host_uid_hash, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> value, + hd -> group -> options + [DHO_DHCP_CLIENT_IDENTIFIER] -> len, + (unsigned char *)hd); + } + } +} + +struct host_decl *find_hosts_by_haddr (htype, haddr, hlen) + int htype; + unsigned char *haddr; + int hlen; +{ + struct host_decl *foo; + + foo = (struct host_decl *)hash_lookup (host_hw_addr_hash, + haddr, hlen); + return foo; +} + +struct host_decl *find_hosts_by_uid (data, len) + unsigned char *data; + int len; +{ + struct host_decl *foo; + + foo = (struct host_decl *)hash_lookup (host_uid_hash, data, len); + return foo; +} + +/* More than one host_decl can be returned by find_hosts_by_haddr or + find_hosts_by_uid, and each host_decl can have multiple addresses. + Loop through the list of hosts, and then for each host, through the + list of addresses, looking for an address that's in the same shared + network as the one specified. Store the matching address through + the addr pointer, update the host pointer to point at the host_decl + that matched, and return the subnet that matched. */ + +struct subnet *find_host_for_network (host, addr, share) + struct host_decl **host; + struct iaddr *addr; + struct shared_network *share; +{ + int i; + struct subnet *subnet; + struct iaddr ip_address; + struct host_decl *hp; + + for (hp = *host; hp; hp = hp -> n_ipaddr) { + if (!hp -> fixed_addr || !tree_evaluate (hp -> fixed_addr)) + continue; + for (i = 0; i < hp -> fixed_addr -> len; i += 4) { + ip_address.len = 4; + memcpy (ip_address.iabuf, + hp -> fixed_addr -> value + i, 4); + subnet = find_grouped_subnet (share, ip_address); + if (subnet) { + *addr = ip_address; + *host = hp; + return subnet; + } + } + } + return (struct subnet *)0; +} + +void new_address_range (low, high, subnet, dynamic) + struct iaddr low, high; + struct subnet *subnet; + int dynamic; +{ + struct lease *address_range, *lp, *plp; + struct iaddr net; + int min, max, i; + char lowbuf [16], highbuf [16], netbuf [16]; + struct shared_network *share = subnet -> shared_network; + struct hostent *h; + struct in_addr ia; + + /* All subnets should have attached shared network structures. */ + if (!share) { + strcpy (netbuf, piaddr (subnet -> net)); + error ("No shared network for network %s (%s)", + netbuf, piaddr (subnet -> netmask)); + } + + /* Initialize the hash table if it hasn't been done yet. */ + if (!lease_uid_hash) + lease_uid_hash = new_hash (); + if (!lease_ip_addr_hash) + lease_ip_addr_hash = new_hash (); + if (!lease_hw_addr_hash) + lease_hw_addr_hash = new_hash (); + + /* Make sure that high and low addresses are in same subnet. */ + net = subnet_number (low, subnet -> netmask); + if (!addr_eq (net, subnet_number (high, subnet -> netmask))) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + strcpy (netbuf, piaddr (subnet -> netmask)); + error ("Address range %s to %s, netmask %s spans %s!", + lowbuf, highbuf, netbuf, "multiple subnets"); + } + + /* Make sure that the addresses are on the correct subnet. */ + if (!addr_eq (net, subnet -> net)) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + strcpy (netbuf, piaddr (subnet -> netmask)); + error ("Address range %s to %s not on net %s/%s!", + lowbuf, highbuf, piaddr (subnet -> net), netbuf); + } + + /* Get the high and low host addresses... */ + max = host_addr (high, subnet -> netmask); + min = host_addr (low, subnet -> netmask); + + /* Allow range to be specified high-to-low as well as low-to-high. */ + if (min > max) { + max = min; + min = host_addr (high, subnet -> netmask); + } + + /* Get a lease structure for each address in the range. */ + address_range = new_leases (max - min + 1, "new_address_range"); + if (!address_range) { + strcpy (lowbuf, piaddr (low)); + strcpy (highbuf, piaddr (high)); + error ("No memory for address range %s-%s.", lowbuf, highbuf); + } + memset (address_range, 0, (sizeof *address_range) * (max - min + 1)); + + /* Fill in the last lease if it hasn't been already... */ + if (!share -> last_lease) { + share -> last_lease = &address_range [0]; + } + + /* Fill out the lease structures with some minimal information. */ + for (i = 0; i < max - min + 1; i++) { + address_range [i].ip_addr = + ip_addr (subnet -> net, subnet -> netmask, i + min); + address_range [i].starts = + address_range [i].timestamp = MIN_TIME; + address_range [i].ends = MIN_TIME; + address_range [i].subnet = subnet; + address_range [i].shared_network = share; + address_range [i].flags = dynamic ? DYNAMIC_BOOTP_OK : 0; + + memcpy (&ia, address_range [i].ip_addr.iabuf, 4); + + if (subnet -> group -> get_lease_hostnames) { + h = gethostbyaddr ((char *)&ia, sizeof ia, AF_INET); + if (!h) + warn ("No hostname for %s", inet_ntoa (ia)); + else { + address_range [i].hostname = + malloc (strlen (h -> h_name) + 1); + if (!address_range [i].hostname) + error ("no memory for hostname %s.", + h -> h_name); + strcpy (address_range [i].hostname, + h -> h_name); + } + } + + /* Link this entry into the list. */ + address_range [i].next = share -> leases; + address_range [i].prev = (struct lease *)0; + share -> leases = &address_range [i]; + if (address_range [i].next) + address_range [i].next -> prev = share -> leases; + add_hash (lease_ip_addr_hash, + address_range [i].ip_addr.iabuf, + address_range [i].ip_addr.len, + (unsigned char *)&address_range [i]); + } + + /* Find out if any dangling leases are in range... */ + plp = (struct lease *)0; + for (lp = dangling_leases; lp; lp = lp -> next) { + struct iaddr lnet; + int lhost; + + lnet = subnet_number (lp -> ip_addr, subnet -> netmask); + lhost = host_addr (lp -> ip_addr, subnet -> netmask); + + /* If it's in range, fill in the real lease structure with + the dangling lease's values, and remove the lease from + the list of dangling leases. */ + if (addr_eq (lnet, subnet -> net) && + lhost >= i && lhost <= max) { + if (plp) { + plp -> next = lp -> next; + } else { + dangling_leases = lp -> next; + } + lp -> next = (struct lease *)0; + address_range [lhost - i].hostname = lp -> hostname; + address_range [lhost - i].client_hostname = + lp -> client_hostname; + supersede_lease (&address_range [lhost - i], lp, 0); + free_lease (lp, "new_address_range"); + } else + plp = lp; + } +} + +struct subnet *find_subnet (addr) + struct iaddr addr; +{ + struct subnet *rv; + + for (rv = subnets; rv; rv = rv -> next_subnet) { + if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) + return rv; + } + return (struct subnet *)0; +} + +struct subnet *find_grouped_subnet (share, addr) + struct shared_network *share; + struct iaddr addr; +{ + struct subnet *rv; + + for (rv = share -> subnets; rv; rv = rv -> next_sibling) { + if (addr_eq (subnet_number (addr, rv -> netmask), rv -> net)) + return rv; + } + return (struct subnet *)0; +} + +/* Enter a new subnet into the subnet list. */ + +void enter_subnet (subnet) + struct subnet *subnet; +{ + struct subnet *scan; + + /* Check for duplicates... */ + for (scan = subnets; scan; scan = scan -> next_subnet) { + if (addr_eq (subnet_number (subnet -> net, scan -> netmask), + scan -> net) || + addr_eq (subnet_number (scan -> net, subnet -> netmask), + subnet -> net)) { + char n1buf [16]; + int i, j; + for (i = 0; i < 32; i++) + if (subnet -> netmask.iabuf [3 - (i >> 3)] + & (1 << (i & 7))) + break; + for (j = 0; j < 32; j++) + if (scan -> netmask.iabuf [3 - (j >> 3)] + & (1 << (j & 7))) + break; + strcpy (n1buf, piaddr (subnet -> net)); + error ("subnet %s/%d conflicts with subnet %s/%d", + n1buf, i, piaddr (scan -> net), j); + } + } + + /* XXX Sort the nets into a balanced tree to make searching quicker. */ + subnet -> next_subnet = subnets; + subnets = subnet; +} + +/* Enter a new shared network into the shared network list. */ + +void enter_shared_network (share) + struct shared_network *share; +{ + /* XXX Sort the nets into a balanced tree to make searching quicker. */ + share -> next = shared_networks; + shared_networks = share; +} + +/* Enter a lease into the system. This is called by the parser each + time it reads in a new lease. If the subnet for that lease has + already been read in (usually the case), just update that lease; + otherwise, allocate temporary storage for the lease and keep it around + until we're done reading in the config file. */ + +void enter_lease (lease) + struct lease *lease; +{ + struct lease *comp = find_lease_by_ip_addr (lease -> ip_addr); + + /* If we don't have a place for this lease yet, save it for + later. */ + if (!comp) { + comp = new_lease ("enter_lease"); + if (!comp) { + error ("No memory for lease %s\n", + piaddr (lease -> ip_addr)); + } + *comp = *lease; + comp -> next = dangling_leases; + comp -> prev = (struct lease *)0; + dangling_leases = comp; + } else { + /* Record the hostname information in the lease. */ + comp -> hostname = lease -> hostname; + comp -> client_hostname = lease -> client_hostname; + supersede_lease (comp, lease, 0); + } +} + +/* Replace the data in an existing lease with the data in a new lease; + adjust hash tables to suit, and insertion sort the lease into the + list of leases by expiry time so that we can always find the oldest + lease. */ + +int supersede_lease (comp, lease, commit) + struct lease *comp, *lease; + int commit; +{ + int enter_uid = 0; + int enter_hwaddr = 0; + struct lease *lp; + + /* Static leases are not currently kept in the database... */ + if (lease -> flags & STATIC_LEASE) + return 1; + + /* If the existing lease hasn't expired and has a different + unique identifier or, if it doesn't have a unique + identifier, a different hardware address, then the two + leases are in conflict. If the existing lease has a uid + and the new one doesn't, but they both have the same + hardware address, and dynamic bootp is allowed on this + lease, then we allow that, in case a dynamic BOOTP lease is + requested *after* a DHCP lease has been assigned. */ + + if (!(lease -> flags & ABANDONED_LEASE) && + comp -> ends > cur_time && + (((comp -> uid && lease -> uid) && + (comp -> uid_len != lease -> uid_len || + memcmp (comp -> uid, lease -> uid, comp -> uid_len))) || + (!comp -> uid && + ((comp -> hardware_addr.htype != + lease -> hardware_addr.htype) || + (comp -> hardware_addr.hlen != + lease -> hardware_addr.hlen) || + memcmp (comp -> hardware_addr.haddr, + lease -> hardware_addr.haddr, + comp -> hardware_addr.hlen))))) { + warn ("Lease conflict at %s", + piaddr (comp -> ip_addr)); + return 0; + } else { + /* If there's a Unique ID, dissociate it from the hash + table and free it if necessary. */ + if (comp -> uid) { + uid_hash_delete (comp); + enter_uid = 1; + if (comp -> uid != &comp -> uid_buf [0]) { + free (comp -> uid); + comp -> uid_max = 0; + comp -> uid_len = 0; + } + comp -> uid = (unsigned char *)0; + } else + enter_uid = 1; + + if (comp -> hardware_addr.htype && + ((comp -> hardware_addr.hlen != + lease -> hardware_addr.hlen) || + (comp -> hardware_addr.htype != + lease -> hardware_addr.htype) || + memcmp (comp -> hardware_addr.haddr, + lease -> hardware_addr.haddr, + comp -> hardware_addr.hlen))) { + hw_hash_delete (comp); + enter_hwaddr = 1; + } else if (!comp -> hardware_addr.htype) + enter_hwaddr = 1; + + /* Copy the data files, but not the linkages. */ + comp -> starts = lease -> starts; + comp -> timestamp = lease -> timestamp; + if (lease -> uid) { + if (lease -> uid_len < sizeof (lease -> uid_buf)) { + memcpy (comp -> uid_buf, + lease -> uid, lease -> uid_len); + comp -> uid = &comp -> uid_buf [0]; + comp -> uid_max = sizeof comp -> uid_buf; + } else if (lease -> uid != &lease -> uid_buf [0]) { + comp -> uid = lease -> uid; + comp -> uid_max = lease -> uid_max; + lease -> uid = (unsigned char *)0; + lease -> uid_max = 0; + } else { + error ("corrupt lease uid."); /* XXX */ + } + } else { + comp -> uid = (unsigned char *)0; + comp -> uid_max = 0; + } + comp -> uid_len = lease -> uid_len; + comp -> host = lease -> host; + comp -> hardware_addr = lease -> hardware_addr; + comp -> flags = ((lease -> flags & ~PERSISTENT_FLAGS) | + (comp -> flags & ~EPHEMERAL_FLAGS)); + + /* Record the lease in the uid hash if necessary. */ + if (enter_uid && lease -> uid) { + uid_hash_add (comp); + } + + /* Record it in the hardware address hash if necessary. */ + if (enter_hwaddr && lease -> hardware_addr.htype) { + hw_hash_add (comp); + } + + /* Remove the lease from its current place in the + timeout sequence. */ + if (comp -> prev) { + comp -> prev -> next = comp -> next; + } else { + comp -> shared_network -> leases = comp -> next; + } + if (comp -> next) { + comp -> next -> prev = comp -> prev; + } + if (comp -> shared_network -> last_lease == comp) { + comp -> shared_network -> last_lease = comp -> prev; + } + + /* Find the last insertion point... */ + if (comp == comp -> shared_network -> insertion_point || + !comp -> shared_network -> insertion_point) { + lp = comp -> shared_network -> leases; + } else { + lp = comp -> shared_network -> insertion_point; + } + + if (!lp) { + /* Nothing on the list yet? Just make comp the + head of the list. */ + comp -> shared_network -> leases = comp; + comp -> shared_network -> last_lease = comp; + } else if (lp -> ends > lease -> ends) { + /* Skip down the list until we run out of list + or find a place for comp. */ + while (lp -> next && lp -> ends > lease -> ends) { + lp = lp -> next; + } + if (lp -> ends > lease -> ends) { + /* If we ran out of list, put comp + at the end. */ + lp -> next = comp; + comp -> prev = lp; + comp -> next = (struct lease *)0; + comp -> shared_network -> last_lease = comp; + } else { + /* If we didn't, put it between lp and + the previous item on the list. */ + if ((comp -> prev = lp -> prev)) + comp -> prev -> next = comp; + comp -> next = lp; + lp -> prev = comp; + } + } else { + /* Skip up the list until we run out of list + or find a place for comp. */ + while (lp -> prev && lp -> ends < lease -> ends) { + lp = lp -> prev; + } + if (lp -> ends < lease -> ends) { + /* If we ran out of list, put comp + at the beginning. */ + lp -> prev = comp; + comp -> next = lp; + comp -> prev = (struct lease *)0; + comp -> shared_network -> leases = comp; + } else { + /* If we didn't, put it between lp and + the next item on the list. */ + if ((comp -> next = lp -> next)) + comp -> next -> prev = comp; + comp -> prev = lp; + lp -> next = comp; + } + } + comp -> shared_network -> insertion_point = comp; + comp -> ends = lease -> ends; + } + + /* Return zero if we didn't commit the lease to permanent storage; + nonzero if we did. */ + return commit && write_lease (comp) && commit_leases (); +} + +/* Release the specified lease and re-hash it as appropriate. */ + +void release_lease (lease) + struct lease *lease; +{ + struct lease lt; + + lt = *lease; + lt.ends = cur_time; + supersede_lease (lease, <, 1); +} + +/* Abandon the specified lease (set its timeout to infinity and its + particulars to zero, and re-hash it as appropriate. */ + +void abandon_lease (lease, message) + struct lease *lease; + char *message; +{ + struct lease lt; + + lease -> flags |= ABANDONED_LEASE; + lt = *lease; + lt.ends = cur_time; + warn ("Abandoning IP address %s: %s", + piaddr (lease -> ip_addr), message); + lt.hardware_addr.htype = 0; + lt.hardware_addr.hlen = 0; + lt.uid = (unsigned char *)0; + lt.uid_len = 0; + supersede_lease (lease, <, 1); +} + +/* Locate the lease associated with a given IP address... */ + +struct lease *find_lease_by_ip_addr (addr) + struct iaddr addr; +{ + struct lease *lease = (struct lease *)hash_lookup (lease_ip_addr_hash, + addr.iabuf, + addr.len); + return lease; +} + +struct lease *find_lease_by_uid (uid, len) + unsigned char *uid; + int len; +{ + struct lease *lease = (struct lease *)hash_lookup (lease_uid_hash, + uid, len); + return lease; +} + +struct lease *find_lease_by_hw_addr (hwaddr, hwlen) + unsigned char *hwaddr; + int hwlen; +{ + struct lease *lease = (struct lease *)hash_lookup (lease_hw_addr_hash, + hwaddr, hwlen); + return lease; +} + +/* Add the specified lease to the uid hash. */ + +void uid_hash_add (lease) + struct lease *lease; +{ + struct lease *head = + find_lease_by_uid (lease -> uid, lease -> uid_len); + struct lease *scan; + +#ifdef DEBUG + if (lease -> n_uid) + abort (); +#endif + + /* If it's not in the hash, just add it. */ + if (!head) + add_hash (lease_uid_hash, lease -> uid, + lease -> uid_len, (unsigned char *)lease); + else { + /* Otherwise, attach it to the end of the list. */ + for (scan = head; scan -> n_uid; scan = scan -> n_uid) +#ifdef DEBUG + if (scan == lease) + abort () +#endif + ; + scan -> n_uid = lease; + } +} + +/* Delete the specified lease from the uid hash. */ + +void uid_hash_delete (lease) + struct lease *lease; +{ + struct lease *head = + find_lease_by_uid (lease -> uid, lease -> uid_len); + struct lease *scan; + + /* If it's not in the hash, we have no work to do. */ + if (!head) { + lease -> n_uid = (struct lease *)0; + return; + } + + /* If the lease we're freeing is at the head of the list, + remove the hash table entry and add a new one with the + next lease on the list (if there is one). */ + if (head == lease) { + delete_hash_entry (lease_uid_hash, + lease -> uid, lease -> uid_len); + if (lease -> n_uid) + add_hash (lease_uid_hash, + lease -> n_uid -> uid, + lease -> n_uid -> uid_len, + (unsigned char *)(lease -> n_uid)); + } else { + /* Otherwise, look for the lease in the list of leases + attached to the hash table entry, and remove it if + we find it. */ + for (scan = head; scan -> n_uid; scan = scan -> n_uid) { + if (scan -> n_uid == lease) { + scan -> n_uid = scan -> n_uid -> n_uid; + break; + } + } + } + lease -> n_uid = (struct lease *)0; +} + +/* Add the specified lease to the hardware address hash. */ + +void hw_hash_add (lease) + struct lease *lease; +{ + struct lease *head = + find_lease_by_hw_addr (lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + struct lease *scan; + + /* If it's not in the hash, just add it. */ + if (!head) + add_hash (lease_hw_addr_hash, + lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen, + (unsigned char *)lease); + else { + /* Otherwise, attach it to the end of the list. */ + for (scan = head; scan -> n_hw; scan = scan -> n_hw) + ; + scan -> n_hw = lease; + } +} + +/* Delete the specified lease from the hardware address hash. */ + +void hw_hash_delete (lease) + struct lease *lease; +{ + struct lease *head = + find_lease_by_hw_addr (lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + struct lease *scan; + + /* If it's not in the hash, we have no work to do. */ + if (!head) { + lease -> n_hw = (struct lease *)0; + return; + } + + /* If the lease we're freeing is at the head of the list, + remove the hash table entry and add a new one with the + next lease on the list (if there is one). */ + if (head == lease) { + delete_hash_entry (lease_hw_addr_hash, + lease -> hardware_addr.haddr, + lease -> hardware_addr.hlen); + if (lease -> n_hw) + add_hash (lease_hw_addr_hash, + lease -> n_hw -> hardware_addr.haddr, + lease -> n_hw -> hardware_addr.hlen, + (unsigned char *)(lease -> n_hw)); + } else { + /* Otherwise, look for the lease in the list of leases + attached to the hash table entry, and remove it if + we find it. */ + for (scan = head; scan -> n_hw; scan = scan -> n_hw) { + if (scan -> n_hw == lease) { + scan -> n_hw = scan -> n_hw -> n_hw; + break; + } + } + } + lease -> n_hw = (struct lease *)0; +} + + +struct class *add_class (type, name) + int type; + char *name; +{ + struct class *class = new_class ("add_class"); + char *tname = (char *)malloc (strlen (name) + 1); + + if (!vendor_class_hash) + vendor_class_hash = new_hash (); + if (!user_class_hash) + user_class_hash = new_hash (); + + if (!tname || !class || !vendor_class_hash || !user_class_hash) + return (struct class *)0; + + memset (class, 0, sizeof *class); + strcpy (tname, name); + class -> name = tname; + + if (type) + add_hash (user_class_hash, + (unsigned char *)tname, strlen (tname), + (unsigned char *)class); + else + add_hash (vendor_class_hash, + (unsigned char *)tname, strlen (tname), + (unsigned char *)class); + return class; +} + +struct class *find_class (type, name, len) + int type; + unsigned char *name; + int len; +{ + struct class *class = + (struct class *)hash_lookup (type + ? user_class_hash + : vendor_class_hash, name, len); + return class; +} + +struct group *clone_group (group, caller) + struct group *group; + char *caller; +{ + struct group *g = new_group (caller); + if (!g) + error ("%s: can't allocate new group", caller); + *g = *group; + return g; +} + +/* Write all interesting leases to permanent storage. */ + +void write_leases () +{ + struct lease *l; + struct shared_network *s; + + for (s = shared_networks; s; s = s -> next) { + for (l = s -> leases; l; l = l -> next) { + if (l -> hardware_addr.hlen || + l -> uid_len || + (l -> flags & ABANDONED_LEASE)) + if (!write_lease (l)) + error ("Can't rewrite lease database"); + } + } + if (!commit_leases ()) + error ("Can't commit leases to new database: %m"); +} + +void dump_subnets () +{ + struct lease *l; + struct shared_network *s; + struct subnet *n; + + for (s = shared_networks; s; s = s -> next) { + for (n = subnets; n; n = n -> next_sibling) { + debug ("Subnet %s", piaddr (n -> net)); + debug (" netmask %s", + piaddr (n -> netmask)); + } + for (l = s -> leases; l; l = l -> next) { + print_lease (l); + } + debug ("Last Lease:"); + print_lease (s -> last_lease); + } +} diff --git a/contrib/isc-dhcp/common/nit.c b/contrib/isc-dhcp/common/nit.c new file mode 100644 index 0000000..0633f1d --- /dev/null +++ b/contrib/isc-dhcp/common/nit.c @@ -0,0 +1,347 @@ +/* nit.c + + Network Interface Tap (NIT) network interface code, by Ted Lemon + with one crucial tidbit of help from Stu Grossmen. */ + +/* + * Copyright (c) 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''. */ + +#ifndef lint +static char copyright[] = +"$Id: nit.c,v 1.15 1997/10/20 21:47:13 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#if defined (USE_NIT_SEND) || defined (USE_NIT_RECEIVE) +#include <sys/ioctl.h> +#include <sys/uio.h> + +#include <sys/time.h> +#include <net/nit.h> +#include <net/nit_if.h> +#include <net/nit_pf.h> +#include <net/nit_buf.h> +#include <sys/stropts.h> +#include <net/packetfilt.h> + +#include <netinet/in_systm.h> +#include "includes/netinet/ip.h" +#include "includes/netinet/udp.h" +#include "includes/netinet/if_ether.h" + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_NIT_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +} +#endif + +#ifdef USE_NIT_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +} +#endif + +/* 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_nit (info) + struct interface_info *info; +{ + int sock; + char filename[50]; + struct ifreq ifr; + struct strioctl sio; + + /* Open a NIT device */ + sock = open ("/dev/nit", O_RDWR); + if (sock < 0) + error ("Can't open NIT device for %s: %m", info -> name); + + /* Set the NIT device to point at this interface. */ + sio.ic_cmd = NIOCBIND; + sio.ic_len = sizeof *(info -> ifp); + sio.ic_dp = (char *)(info -> ifp); + sio.ic_timout = INFTIM; + if (ioctl (sock, I_STR, &sio) < 0) + error ("Can't attach interface %s to nit device: %m", + info -> name); + + /* Get the low-level address... */ + sio.ic_cmd = SIOCGIFADDR; + sio.ic_len = sizeof ifr; + sio.ic_dp = (char *)𝔦 + sio.ic_timout = INFTIM; + if (ioctl (sock, I_STR, &sio) < 0) + error ("Can't get physical layer address for %s: %m", + info -> name); + + /* XXX code below assumes ethernet interface! */ + info -> hw_address.hlen = 6; + info -> hw_address.htype = ARPHRD_ETHER; + memcpy (info -> hw_address.haddr, ifr.ifr_ifru.ifru_addr.sa_data, 6); + + if (ioctl (sock, I_PUSH, "pf") < 0) + error ("Can't push packet filter onto NIT for %s: %m", + info -> name); + + return sock; +} +#endif /* USE_NIT_SEND || USE_NIT_RECEIVE */ + +#ifdef USE_NIT_SEND +void if_register_send (info) + struct interface_info *info; +{ + /* If we're using the nit API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_NIT_RECEIVE + struct packetfilt pf; + struct strioctl sio; + + info -> wfdesc = if_register_nit (info); + + pf.Pf_Priority = 0; + pf.Pf_FilterLen = 1; + pf.Pf_Filter [0] = ENF_PUSHZERO; + + /* Set up an NIT filter that rejects everything... */ + sio.ic_cmd = NIOCSETF; + sio.ic_len = sizeof pf; + sio.ic_dp = (char *)&pf; + sio.ic_timout = INFTIM; + if (ioctl (info -> wfdesc, I_STR, &sio) < 0) + error ("Can't set NIT filter: %m"); +#else + info -> wfdesc = info -> rfdesc; +#endif + if (!quiet_interface_discovery) + note ("Sending on NIT/%s/%s", + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_NIT_SEND */ + +#ifdef USE_NIT_RECEIVE +/* Packet filter program... + XXX Changes to the filter program may require changes to the constant + offsets used in if_register_send to patch the NIT program! XXX */ + +void if_register_receive (info) + struct interface_info *info; +{ + int flag = 1; + u_int32_t x; + struct packetfilt pf; + struct strioctl sio; + u_int16_t addr [2]; + struct timeval t; + + /* Open a NIT device and hang it on this interface... */ + info -> rfdesc = if_register_nit (info); + + /* Set the snap length to 0, which means always take the whole + packet. */ + x = 0; + if (ioctl (info -> rfdesc, NIOCSSNAP, &x) < 0) + error ("Can't set NIT snap length on %s: %m", info -> name); + + /* Set the stream to byte stream mode */ + if (ioctl (info -> rfdesc, I_SRDOPT, RMSGN) != 0) + note ("I_SRDOPT failed on %s: %m", info -> name); + +#if 0 + /* Push on the chunker... */ + if (ioctl (info -> rfdesc, I_PUSH, "nbuf") < 0) + error ("Can't push chunker onto NIT STREAM: %m"); + + /* Set the timeout to zero. */ + t.tv_sec = 0; + t.tv_usec = 0; + if (ioctl (info -> rfdesc, NIOCSTIME, &t) < 0) + error ("Can't set chunk timeout: %m"); +#endif + + /* Ask for no header... */ + x = 0; + if (ioctl (info -> rfdesc, NIOCSFLAGS, &x) < 0) + error ("Can't set NIT flags on %s: %m", info -> name); + + /* Set up the NIT filter program. */ + /* XXX Unlike the BPF filter program, this one won't work if the + XXX IP packet is fragmented or if there are options on the IP + XXX header. */ + pf.Pf_Priority = 0; + pf.Pf_FilterLen = 0; + + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 6; + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (ETHERTYPE_IP); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (IPPROTO_UDP); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 11; + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_AND; + pf.Pf_Filter [pf.Pf_FilterLen++] = htons (0xFF); + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHWORD + 18; + pf.Pf_Filter [pf.Pf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; + pf.Pf_Filter [pf.Pf_FilterLen++] = local_port; + + /* Install the filter... */ + sio.ic_cmd = NIOCSETF; + sio.ic_len = sizeof pf; + sio.ic_dp = (char *)&pf; + sio.ic_timout = INFTIM; + if (ioctl (info -> rfdesc, I_STR, &sio) < 0) + error ("Can't set NIT filter on %s: %m", info -> name); + + if (!quiet_interface_discovery) + note ("Listening on NIT/%s/%s", + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_NIT_RECEIVE */ + +#ifdef USE_NIT_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + int bufp; + unsigned char buf [1536 + sizeof (struct sockaddr)]; + struct sockaddr *junk; + struct strbuf ctl, data; + int hw_end; + struct sockaddr_in foo; + + /* Start with the sockaddr struct... */ + junk = (struct sockaddr *)&buf [0]; + bufp = ((unsigned char *)&junk -> sa_data [0]) - &buf [0]; + + /* Assemble the headers... */ + assemble_hw_header (interface, buf, &bufp, hto); + hw_end = bufp; + assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + to -> sin_addr.s_addr, to -> sin_port, + raw, len); + + /* Copy the data into the buffer (yuk). */ + memcpy (buf + bufp, raw, len); + + /* Set up the sockaddr structure... */ +#if USE_SIN_LEN + junk -> sa_len = hw_end - 2; /* XXX */ +#endif + junk -> sa_family = AF_UNSPEC; + +#if 0 /* Already done. */ + memcpy (junk.sa_data, buf, hw_len); +#endif + + /* Set up the msg_buf structure... */ + ctl.buf = (char *)&buf [0]; + ctl.maxlen = ctl.len = hw_end; + data.buf = (char *)&buf [hw_end]; + data.maxlen = data.len = bufp + len - hw_end; + + return putmsg (interface -> wfdesc, &ctl, &data, 0); +} +#endif /* USE_NIT_SEND */ + +#ifdef USE_NIT_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + int nread; + int length = 0; + int offset = 0; + unsigned char ibuf [1536]; + int bufix = 0; + + length = read (interface -> rfdesc, ibuf, sizeof ibuf); + if (length <= 0) + return length; + + /* Decode the physical header... */ + offset = decode_hw_header (interface, ibuf, bufix, hfrom); + + /* If a physical layer checksum failed (dunno of any + physical layer that supports this, but WTH), skip this + packet. */ + if (offset < 0) { + return 0; + } + + bufix += offset; + length -= offset; + + /* Decode the IP and UDP headers... */ + offset = decode_udp_ip_header (interface, ibuf, bufix, + from, (unsigned char *)0, length); + + /* If the IP or UDP checksum was bad, skip the packet... */ + if (offset < 0) + return 0; + + bufix += offset; + length -= offset; + + /* Copy out the data in the packet... */ + memcpy (buf, &ibuf [bufix], length); + return length; +} +#endif diff --git a/contrib/isc-dhcp/common/options.c b/contrib/isc-dhcp/common/options.c new file mode 100644 index 0000000..9d6b7f4 --- /dev/null +++ b/contrib/isc-dhcp/common/options.c @@ -0,0 +1,609 @@ +/* options.c + + 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: options.c,v 1.26.2.3 1998/06/25 21:11:30 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#define DHCP_OPTION_DATA +#include "dhcpd.h" + +/* Parse all available options out of the specified packet. */ + +void parse_options (packet) + struct packet *packet; +{ + /* Initially, zero all option pointers. */ + memset (packet -> options, 0, sizeof (packet -> options)); + + /* If we don't see the magic cookie, there's nothing to parse. */ + if (memcmp (packet -> raw -> options, DHCP_OPTIONS_COOKIE, 4)) { + packet -> options_valid = 0; + return; + } + + /* Go through the options field, up to the end of the packet + or the End field. */ + parse_option_buffer (packet, &packet -> raw -> options [4], + packet -> packet_length - DHCP_FIXED_NON_UDP - 4); + /* If we parsed a DHCP Option Overload option, parse more + options out of the buffer(s) containing them. */ + if (packet -> options_valid + && packet -> options [DHO_DHCP_OPTION_OVERLOAD].data) { + if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 1) + parse_option_buffer (packet, + (unsigned char *) + packet -> raw -> file, + sizeof packet -> raw -> file); + if (packet -> options [DHO_DHCP_OPTION_OVERLOAD].data [0] & 2) + parse_option_buffer (packet, + (unsigned char *) + packet -> raw -> sname, + sizeof packet -> raw -> sname); + } +} + +/* Parse options out of the specified buffer, storing addresses of option + values in packet -> options and setting packet -> options_valid if no + errors are encountered. */ + +void parse_option_buffer (packet, buffer, length) + struct packet *packet; + unsigned char *buffer; + int length; +{ + unsigned char *s, *t; + unsigned char *end = buffer + length; + int len; + int code; + + for (s = buffer; *s != DHO_END && s < end; ) { + code = s [0]; + /* Pad options don't have a length - just skip them. */ + if (code == DHO_PAD) { + ++s; + continue; + } + /* All other fields (except end, see above) have a + one-byte length. */ + len = s [1]; + + /* If the length is outrageous, the options are bad. */ + if (s + len + 2 > end) { + warn ("Option %s length %d overflows input buffer.", + dhcp_options [code].name, + len); + packet -> options_valid = 0; + return; + } + /* If we haven't seen this option before, just make + space for it and copy it there. */ + if (!packet -> options [code].data) { + if (!(t = (unsigned char *)malloc (len + 1))) + error ("Can't allocate storage for option %s.", + dhcp_options [code].name); + /* Copy and NUL-terminate the option (in case it's an + ASCII string. */ + memcpy (t, &s [2], len); + t [len] = 0; + packet -> options [code].len = len; + packet -> options [code].data = t; + } else { + /* If it's a repeat, concatenate it to whatever + we last saw. This is really only required + for clients, but what the heck... */ + t = (unsigned char *) + malloc (len + + packet -> options [code].len + + 1); + if (!t) + error ("Can't expand storage for option %s.", + dhcp_options [code].name); + memcpy (t, packet -> options [code].data, + packet -> options [code].len); + memcpy (t + packet -> options [code].len, + &s [2], len); + packet -> options [code].len += len; + t [packet -> options [code].len] = 0; + free (packet -> options [code].data); + packet -> options [code].data = t; + } + s += len + 2; + } + packet -> options_valid = 1; +} + +/* cons options into a big buffer, and then split them out into the + three seperate buffers if needed. This allows us to cons up a set + of vendor options using the same routine. */ + +int cons_options (inpacket, outpacket, options, overload, terminate, bootpp) + struct packet *inpacket; + struct dhcp_packet *outpacket; + struct tree_cache **options; + int overload; /* Overload flags that may be set. */ + int terminate; + int bootpp; +{ + unsigned char priority_list [300]; + int priority_len; + unsigned char buffer [4096]; /* Really big buffer... */ + int main_buffer_size; + int mainbufix, bufix; + int option_size; + int length; + + /* If the client has provided a maximum DHCP message size, + use that; otherwise, if it's BOOTP, only 64 bytes; otherwise + use up to the minimum IP MTU size (576 bytes). */ + /* XXX if a BOOTP client specifies a max message size, we will + honor it. */ + if (inpacket && inpacket -> options [DHO_DHCP_MAX_MESSAGE_SIZE].data) { + main_buffer_size = + (getUShort (inpacket -> options + [DHO_DHCP_MAX_MESSAGE_SIZE].data) + - DHCP_FIXED_LEN); + /* Enforce a minimum packet size... */ + if (main_buffer_size < (576 - DHCP_FIXED_LEN)) + main_buffer_size = 576 - DHCP_FIXED_LEN; + if (main_buffer_size > sizeof buffer) + main_buffer_size = sizeof buffer; + } else if (bootpp) + main_buffer_size = 64; + else + main_buffer_size = 576 - DHCP_FIXED_LEN; + + /* Preload the option priority list with mandatory options. */ + priority_len = 0; + priority_list [priority_len++] = DHO_DHCP_MESSAGE_TYPE; + priority_list [priority_len++] = DHO_DHCP_SERVER_IDENTIFIER; + priority_list [priority_len++] = DHO_DHCP_LEASE_TIME; + priority_list [priority_len++] = DHO_DHCP_MESSAGE; + + /* If the client has provided a list of options that it wishes + returned, use it to prioritize. Otherwise, prioritize + based on the default priority list. */ + + if (inpacket && + inpacket -> options [DHO_DHCP_PARAMETER_REQUEST_LIST].data) { + int prlen = (inpacket -> + options [DHO_DHCP_PARAMETER_REQUEST_LIST].len); + if (prlen + priority_len > sizeof priority_list) + prlen = (sizeof priority_list) - priority_len; + + memcpy (&priority_list [priority_len], + inpacket -> options + [DHO_DHCP_PARAMETER_REQUEST_LIST].data, prlen); + priority_len += prlen; + } else { + memcpy (&priority_list [priority_len], + dhcp_option_default_priority_list, + sizeof_dhcp_option_default_priority_list); + priority_len += sizeof_dhcp_option_default_priority_list; + } + + /* Copy the options into the big buffer... */ + option_size = store_options (buffer, + (main_buffer_size - 7 + + ((overload & 1) ? DHCP_FILE_LEN : 0) + + ((overload & 2) ? DHCP_SNAME_LEN : 0)), + options, priority_list, priority_len, + main_buffer_size, + (main_buffer_size + + ((overload & 1) ? DHCP_FILE_LEN : 0)), + terminate); + + /* Put the cookie up front... */ + memcpy (outpacket -> options, DHCP_OPTIONS_COOKIE, 4); + mainbufix = 4; + + /* If we're going to have to overload, store the overload + option at the beginning. If we can, though, just store the + whole thing in the packet's option buffer and leave it at + that. */ + if (option_size <= main_buffer_size - mainbufix) { + memcpy (&outpacket -> options [mainbufix], + buffer, option_size); + mainbufix += option_size; + if (mainbufix < main_buffer_size) + outpacket -> options [mainbufix++] + = DHO_END; + length = DHCP_FIXED_NON_UDP + mainbufix; + } else { + outpacket -> options [mainbufix++] = + DHO_DHCP_OPTION_OVERLOAD; + outpacket -> options [mainbufix++] = 1; + if (option_size > main_buffer_size - mainbufix + DHCP_FILE_LEN) + outpacket -> options [mainbufix++] = 3; + else + outpacket -> options [mainbufix++] = 1; + + memcpy (&outpacket -> options [mainbufix], + buffer, main_buffer_size - mainbufix); + bufix = main_buffer_size - mainbufix; + length = DHCP_FIXED_NON_UDP + mainbufix; + if (overload & 1) { + if (option_size - bufix <= DHCP_FILE_LEN) { + memcpy (outpacket -> file, + &buffer [bufix], option_size - bufix); + mainbufix = option_size - bufix; + if (mainbufix < DHCP_FILE_LEN) + outpacket -> file [mainbufix++] + = DHO_END; + while (mainbufix < DHCP_FILE_LEN) + outpacket -> file [mainbufix++] + = DHO_PAD; + } else { + memcpy (outpacket -> file, + &buffer [bufix], DHCP_FILE_LEN); + bufix += DHCP_FILE_LEN; + } + } + if ((overload & 2) && option_size < bufix) { + memcpy (outpacket -> sname, + &buffer [bufix], option_size - bufix); + + mainbufix = option_size - bufix; + if (mainbufix < DHCP_SNAME_LEN) + outpacket -> file [mainbufix++] + = DHO_END; + while (mainbufix < DHCP_SNAME_LEN) + outpacket -> file [mainbufix++] + = DHO_PAD; + } + } + return length; +} + +/* Store all the requested options into the requested buffer. */ + +int store_options (buffer, buflen, options, priority_list, priority_len, + first_cutoff, second_cutoff, terminate) + unsigned char *buffer; + int buflen; + struct tree_cache **options; + unsigned char *priority_list; + int priority_len; + int first_cutoff, second_cutoff; + int terminate; +{ + int bufix = 0; + int option_stored [256]; + int i; + int ix; + int tto; + + /* Zero out the stored-lengths array. */ + memset (option_stored, 0, sizeof option_stored); + + /* Copy out the options in the order that they appear in the + priority list... */ + for (i = 0; i < priority_len; i++) { + /* Code for next option to try to store. */ + int code = priority_list [i]; + int optstart; + + /* Number of bytes left to store (some may already + have been stored by a previous pass). */ + int length; + + /* If no data is available for this option, skip it. */ + if (!options [code]) { + continue; + } + + /* The client could ask for things that are mandatory, + in which case we should avoid storing them twice... */ + if (option_stored [code]) + continue; + option_stored [code] = 1; + + /* Find the value of the option... */ + if (!tree_evaluate (options [code])) { + continue; + } + + /* We should now have a constant length for the option. */ + length = options [code] -> len; + + /* Do we add a NUL? */ + if (terminate && dhcp_options [code].format [0] == 't') { + length++; + tto = 1; + } else { + tto = 0; + } + + /* Try to store the option. */ + + /* If the option's length is more than 255, we must store it + in multiple hunks. Store 255-byte hunks first. However, + in any case, if the option data will cross a buffer + boundary, split it across that boundary. */ + + ix = 0; + + optstart = bufix; + while (length) { + unsigned char incr = length > 255 ? 255 : length; + + /* If this hunk of the buffer will cross a + boundary, only go up to the boundary in this + pass. */ + if (bufix < first_cutoff && + bufix + incr > first_cutoff) + incr = first_cutoff - bufix; + else if (bufix < second_cutoff && + bufix + incr > second_cutoff) + incr = second_cutoff - bufix; + + /* If this option is going to overflow the buffer, + skip it. */ + if (bufix + 2 + incr > buflen) { + bufix = optstart; + break; + } + + /* Everything looks good - copy it in! */ + buffer [bufix] = code; + buffer [bufix + 1] = incr; + if (tto && incr == length) { + memcpy (buffer + bufix + 2, + options [code] -> value + ix, + incr - 1); + buffer [bufix + 2 + incr - 1] = 0; + } else { + memcpy (buffer + bufix + 2, + options [code] -> value + ix, incr); + } + length -= incr; + ix += incr; + bufix += 2 + incr; + } + } + return bufix; +} + +/* Format the specified option so that a human can easily read it. */ + +char *pretty_print_option (code, data, len, emit_commas, emit_quotes) + unsigned int code; + unsigned char *data; + int len; + int emit_commas; + int emit_quotes; +{ + static char optbuf [32768]; /* XXX */ + int hunksize = 0; + int numhunk = -1; + int numelem = 0; + char fmtbuf [32]; + int i, j; + char *op = optbuf; + unsigned char *dp = data; + struct in_addr foo; + char comma; + + /* Code should be between 0 and 255. */ + if (code > 255) + error ("pretty_print_option: bad code %d\n", code); + + if (emit_commas) + comma = ','; + else + comma = ' '; + + /* Figure out the size of the data. */ + for (i = 0; dhcp_options [code].format [i]; i++) { + if (!numhunk) { + warn ("%s: Excess information in format string: %s\n", + dhcp_options [code].name, + &(dhcp_options [code].format [i])); + break; + } + numelem++; + fmtbuf [i] = dhcp_options [code].format [i]; + switch (dhcp_options [code].format [i]) { + case 'A': + --numelem; + fmtbuf [i] = 0; + numhunk = 0; + break; + case 'X': + fmtbuf [i] = 'x'; + fmtbuf [i + 1] = 0; + hunksize++; + numhunk = 0; + comma = ':'; + break; + case 't': + fmtbuf [i] = 't'; + fmtbuf [i + 1] = 0; + numhunk = -2; + break; + case 'I': + case 'l': + case 'L': + hunksize += 4; + break; + case 's': + case 'S': + hunksize += 2; + break; + case 'b': + case 'B': + case 'f': + hunksize++; + break; + case 'e': + break; + default: + warn ("%s: garbage in format string: %s\n", + dhcp_options [code].name, + &(dhcp_options [code].format [i])); + break; + } + } + + /* Check for too few bytes... */ + if (hunksize > len) { + warn ("%s: expecting at least %d bytes; got %d", + dhcp_options [code].name, + hunksize, len); + return "<error>"; + } + /* Check for too many bytes... */ + if (numhunk == -1 && hunksize < len) + warn ("%s: %d extra bytes", + dhcp_options [code].name, + len - hunksize); + + /* If this is an array, compute its size. */ + if (!numhunk) + numhunk = len / hunksize; + /* See if we got an exact number of hunks. */ + if (numhunk > 0 && numhunk * hunksize < len) + warn ("%s: %d extra bytes at end of array\n", + dhcp_options [code].name, + len - numhunk * hunksize); + + /* 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': + if (emit_quotes) + *op++ = '"'; + strcpy (op, (char *)dp); + op += strlen ((char *)dp); + if (emit_quotes) + *op++ = '"'; + *op = 0; + break; + case 'I': + foo.s_addr = htonl (getULong (dp)); + strcpy (op, inet_ntoa (foo)); + dp += 4; + break; + case 'l': + sprintf (op, "%ld", (long)getLong (dp)); + dp += 4; + break; + case 'L': + sprintf (op, "%ld", + (unsigned long)getULong (dp)); + dp += 4; + break; + case 's': + sprintf (op, "%d", getShort (dp)); + dp += 2; + break; + case 'S': + sprintf (op, "%d", getUShort (dp)); + dp += 2; + break; + case 'b': + sprintf (op, "%d", *(char *)dp++); + break; + case 'B': + sprintf (op, "%d", *dp++); + break; + case 'x': + sprintf (op, "%x", *dp++); + break; + case 'f': + strcpy (op, *dp++ ? "true" : "false"); + break; + default: + warn ("Unexpected format code %c", fmtbuf [j]); + } + op += strlen (op); + if (j + 1 < numelem && comma != ':') + *op++ = ' '; + } + if (i + 1 < numhunk) { + *op++ = comma; + } + + } + return optbuf; +} + +void do_packet (interface, packet, len, from_port, from, hfrom) + struct interface_info *interface; + struct dhcp_packet *packet; + int len; + unsigned int from_port; + struct iaddr from; + struct hardware *hfrom; +{ + struct packet tp; + + if (packet -> hlen > sizeof packet -> chaddr) { + note ("Discarding packet with invalid hlen."); + return; + } + + memset (&tp, 0, sizeof tp); + tp.raw = packet; + tp.packet_length = len; + tp.client_port = from_port; + tp.client_addr = from; + tp.interface = interface; + tp.haddr = hfrom; + + parse_options (&tp); + if (tp.options_valid && + tp.options [DHO_DHCP_MESSAGE_TYPE].data) + tp.packet_type = + tp.options [DHO_DHCP_MESSAGE_TYPE].data [0]; + if (tp.packet_type) + dhcp (&tp); + else + bootp (&tp); +} + diff --git a/contrib/isc-dhcp/common/packet.c b/contrib/isc-dhcp/common/packet.c new file mode 100644 index 0000000..069a76b --- /dev/null +++ b/contrib/isc-dhcp/common/packet.c @@ -0,0 +1,311 @@ +/* packet.c + + Packet assembly code, originally contributed by Archie Cobbs. */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: packet.c,v 1.18.2.1 1998/06/26 18:20:44 mellon Exp $ Copyright (c) 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#if defined (PACKET_ASSEMBLY) || defined (PACKET_DECODING) +#include "includes/netinet/ip.h" +#include "includes/netinet/udp.h" +#include "includes/netinet/if_ether.h" +#endif /* PACKET_ASSEMBLY || PACKET_DECODING */ + +/* Compute the easy part of the checksum on a range of bytes. */ + +u_int32_t checksum (buf, nbytes, sum) + unsigned char *buf; + int nbytes; + u_int32_t sum; +{ + int i; + +#ifdef DEBUG_CHECKSUM + debug ("checksum (%x %d %x)", buf, nbytes, sum); +#endif + + /* Checksum all the pairs of bytes first... */ + for (i = 0; i < (nbytes & ~1); i += 2) { +#ifdef DEBUG_CHECKSUM_VERBOSE + debug ("sum = %x", sum); +#endif + sum += (u_int16_t) ntohs(*((u_int16_t *)(buf + i))); + } + + /* 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) { +#ifdef DEBUG_CHECKSUM_VERBOSE + debug ("sum = %x", sum); +#endif + sum += buf [i] << 8; + } + + return sum; +} + +/* Fold the upper sixteen bits of the checksum down into the lower bits, + complement the sum, and then put it into network byte order. */ + +u_int32_t wrapsum (sum) + u_int32_t sum; +{ +#ifdef DEBUG_CHECKSUM + debug ("wrapsum (%x)", sum); +#endif + + while (sum > 0x10000) { + sum = (sum >> 16) + (sum & 0xFFFF); +#ifdef DEBUG_CHECKSUM_VERBOSE + debug ("sum = %x", sum); +#endif + sum += (sum >> 16); +#ifdef DEBUG_CHECKSUM_VERBOSE + debug ("sum = %x", sum); +#endif + } + sum = sum ^ 0xFFFF; +#ifdef DEBUG_CHECKSUM_VERBOSE + debug ("sum = %x", sum); +#endif + +#ifdef DEBUG_CHECKSUM + debug ("wrapsum returns %x", htons (sum)); +#endif + return htons(sum); +} + +#ifdef PACKET_ASSEMBLY +/* Assemble an hardware header... */ +/* XXX currently only supports ethernet; doesn't check for other types. */ + +void assemble_hw_header (interface, buf, bufix, to) + struct interface_info *interface; + unsigned char *buf; + int *bufix; + struct hardware *to; +{ + struct ether_header eh; + + if (to && to -> hlen == 6) /* XXX */ + memcpy (eh.ether_dhost, to -> haddr, sizeof eh.ether_dhost); + else + memset (eh.ether_dhost, 0xff, sizeof (eh.ether_dhost)); + if (interface -> hw_address.hlen == sizeof (eh.ether_shost)) + memcpy (eh.ether_shost, interface -> hw_address.haddr, + sizeof (eh.ether_shost)); + else + memset (eh.ether_shost, 0x00, sizeof (eh.ether_shost)); + +#ifdef BROKEN_FREEBSD_BPF /* Fixed in FreeBSD 2.2 */ + eh.ether_type = ETHERTYPE_IP; +#else + eh.ether_type = htons (ETHERTYPE_IP); +#endif + + memcpy (&buf [*bufix], &eh, sizeof eh); + *bufix += sizeof eh; +} + +/* UDP header and IP header assembled together for convenience. */ + +void assemble_udp_ip_header (interface, buf, bufix, + from, to, port, data, len) + struct interface_info *interface; + unsigned char *buf; + int *bufix; + u_int32_t from; + u_int32_t to; + unsigned int port; + unsigned char *data; + int len; +{ + struct ip ip; + struct udphdr udp; + + /* Fill out the IP header */ + 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 = 16; + ip.ip_p = IPPROTO_UDP; + ip.ip_sum = 0; + ip.ip_src.s_addr = from; + ip.ip_dst.s_addr = to; + + /* Checksum the IP header... */ + ip.ip_sum = wrapsum (checksum ((unsigned char *)&ip, sizeof ip, 0)); + + /* Copy the ip header into the buffer... */ + memcpy (&buf [*bufix], &ip, sizeof ip); + *bufix += sizeof ip; + + /* Fill out the UDP header */ + udp.uh_sport = local_port; /* XXX */ + udp.uh_dport = port; /* XXX */ + udp.uh_ulen = htons(sizeof(udp) + len); + memset (&udp.uh_sum, 0, sizeof udp.uh_sum); + + /* Compute UDP checksums, including the ``pseudo-header'', the UDP + header and the data. */ + +#if 0 + udp.uh_sum = + wrapsum (checksum ((unsigned char *)&udp, sizeof udp, + checksum (data, len, + checksum ((unsigned char *) + &ip.ip_src, + sizeof ip.ip_src, + IPPROTO_UDP + + (u_int32_t) + ntohs (udp.uh_ulen))))); +#endif + + /* Copy the udp header into the buffer... */ + memcpy (&buf [*bufix], &udp, sizeof udp); + *bufix += sizeof udp; +} +#endif /* PACKET_ASSEMBLY */ + +#ifdef PACKET_DECODING +/* Decode a hardware header... */ +/* XXX currently only supports ethernet; doesn't check for other types. */ + +ssize_t decode_hw_header (interface, buf, bufix, from) + struct interface_info *interface; + unsigned char *buf; + int bufix; + struct hardware *from; +{ + struct ether_header eh; + + memcpy (&eh, buf + bufix, sizeof eh); + +#ifdef USERLAND_FILTER + if (ntohs (eh.ether_type) != ETHERTYPE_IP) + return -1; +#endif + memcpy (from -> haddr, eh.ether_shost, sizeof (eh.ether_shost)); + from -> htype = ARPHRD_ETHER; + from -> hlen = sizeof eh.ether_shost; + + return sizeof eh; +} + +/* UDP header and IP header decoded together for convenience. */ + +ssize_t decode_udp_ip_header (interface, buf, bufix, from, data, len) + struct interface_info *interface; + unsigned char *buf; + int bufix; + struct sockaddr_in *from; + unsigned char *data; + int len; +{ + struct ip *ip; + struct udphdr *udp; + u_int32_t ip_len = (buf [bufix] & 0xf) << 2; + u_int32_t sum, usum; + + ip = (struct ip *)(buf + bufix); + udp = (struct udphdr *)(buf + bufix + ip_len); + +#ifdef USERLAND_FILTER + /* Is it a UDP packet? */ + if (ip -> ip_p != IPPROTO_UDP) + return -1; + + /* Is it to the port we're serving? */ + if (udp -> uh_dport != local_port) + return -1; +#endif /* USERLAND_FILTER */ + + /* Check the IP header checksum - it should be zero. */ + if (wrapsum (checksum (buf + bufix, ip_len, 0))) { + note ("Bad IP checksum: %x", + wrapsum (checksum (buf + bufix, sizeof *ip, 0))); + return -1; + } + + /* Copy out the IP source address... */ + memcpy (&from -> sin_addr, &ip -> ip_src, 4); + + /* 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. */ + + if (!data) { + data = buf + bufix + ip_len + sizeof *udp; + len -= ip_len + sizeof *udp; + } + +#if 0 + 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, + sizeof ip -> ip_src, + IPPROTO_UDP + + (u_int32_t) + ntohs (udp -> uh_ulen))))); + + if (usum && usum != sum) { + note ("Bad udp checksum: %x %x", usum, sum); + return -1; + } +#endif + + /* Copy out the port... */ + memcpy (&from -> sin_port, &udp -> uh_sport, sizeof udp -> uh_sport); + + return ip_len + sizeof *udp; +} +#endif /* PACKET_DECODING */ diff --git a/contrib/isc-dhcp/common/parse.c b/contrib/isc-dhcp/common/parse.c new file mode 100644 index 0000000..97bfa87 --- /dev/null +++ b/contrib/isc-dhcp/common/parse.c @@ -0,0 +1,643 @@ +/* parse.c + + 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: parse.c,v 1.2.2.1 1998/06/25 21:11:31 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#include "dhctoken.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 (cfile) + FILE *cfile; +{ + int token; + char *val; + int brace_count = 0; + + do { + token = peek_token (&val, cfile); + if (token == RBRACE) { + if (brace_count) { + token = next_token (&val, cfile); + if (!--brace_count) + return; + } else + return; + } else if (token == LBRACE) { + brace_count++; + } else if (token == SEMI && !brace_count) { + token = next_token (&val, cfile); + return; + } else if (token == EOL) { + /* EOL only happens when parsing /etc/resolv.conf, + and we treat it like a semicolon because the + resolv.conf file is line-oriented. */ + token = next_token (&val, cfile); + return; + } + token = next_token (&val, cfile); + } while (token != EOF); +} + +int parse_semi (cfile) + FILE *cfile; +{ + int token; + char *val; + + token = next_token (&val, cfile); + if (token != SEMI) { + parse_warn ("semicolon expected."); + skip_to_semi (cfile); + return 0; + } + return 1; +} + +/* string-parameter :== STRING SEMI */ + +char *parse_string (cfile) + FILE *cfile; +{ + char *val; + int token; + char *s; + + token = next_token (&val, cfile); + if (token != STRING) { + parse_warn ("filename must be a string"); + skip_to_semi (cfile); + return (char *)0; + } + s = (char *)malloc (strlen (val) + 1); + if (!s) + error ("no memory for string %s.", val); + strcpy (s, val); + + if (!parse_semi (cfile)) + return (char *)0; + return s; +} + +/* hostname :== identifier | hostname DOT identifier */ + +char *parse_host_name (cfile) + FILE *cfile; +{ + char *val; + int token; + int len = 0; + char *s; + char *t; + pair c = (pair)0; + + /* Read a dotted hostname... */ + do { + /* Read a token, which should be an identifier. */ + token = next_token (&val, cfile); + if (!is_identifier (token) && token != NUMBER) { + parse_warn ("expecting an identifier in hostname"); + skip_to_semi (cfile); + return (char *)0; + } + /* Store this identifier... */ + if (!(s = (char *)malloc (strlen (val) + 1))) + error ("can't allocate temp space for hostname."); + strcpy (s, val); + c = cons ((caddr_t)s, c); + len += strlen (s) + 1; + /* Look for a dot; if it's there, keep going, otherwise + we're done. */ + token = peek_token (&val, cfile); + if (token == DOT) + token = next_token (&val, cfile); + } while (token == DOT); + + /* Assemble the hostname together into a string. */ + if (!(s = (char *)malloc (len))) + error ("can't allocate space for hostname."); + t = s + len; + *--t = 0; + while (c) { + pair cdr = c -> cdr; + int l = strlen ((char *)(c -> car)); + t -= l; + memcpy (t, (char *)(c -> car), l); + /* Free up temp space. */ + free (c -> car); + free (c); + c = cdr; + if (t != s) + *--t = '.'; + } + return s; +} + +int parse_ip_addr (cfile, addr) + FILE *cfile; + struct iaddr *addr; +{ + char *val; + int token; + + addr -> len = 4; + if (parse_numeric_aggregate (cfile, addr -> iabuf, + &addr -> len, DOT, 10, 8)) + return 1; + return 0; +} + +/* hardware-parameter :== HARDWARE ETHERNET csns SEMI + csns :== NUMBER | csns COLON NUMBER */ + +void parse_hardware_param (cfile, hardware) + FILE *cfile; + struct hardware *hardware; +{ + char *val; + int token; + int hlen; + unsigned char *t; + + token = next_token (&val, cfile); + switch (token) { + case ETHERNET: + hardware -> htype = HTYPE_ETHER; + break; + case TOKEN_RING: + hardware -> htype = HTYPE_IEEE802; + break; + default: + parse_warn ("expecting a network hardware type"); + skip_to_semi (cfile); + return; + } + + /* Parse the hardware address information. Technically, + it would make a lot of sense to restrict the length of the + data we'll accept here to the length of a particular hardware + address type. Unfortunately, there are some broken clients + out there that put bogus data in the chaddr buffer, and we accept + that data in the lease file rather than simply failing on such + clients. Yuck. */ + hlen = 0; + t = parse_numeric_aggregate (cfile, (unsigned char *)0, &hlen, + COLON, 16, 8); + if (!t) + return; + if (hlen > sizeof hardware -> haddr) { + free (t); + parse_warn ("hardware address too long"); + } else { + hardware -> hlen = hlen; + memcpy ((unsigned char *)&hardware -> haddr [0], + t, hardware -> hlen); + free (t); + } + + token = next_token (&val, cfile); + if (token != SEMI) { + parse_warn ("expecting semicolon."); + skip_to_semi (cfile); + } +} + +/* lease-time :== NUMBER SEMI */ + +void parse_lease_time (cfile, timep) + FILE *cfile; + TIME *timep; +{ + char *val; + int token; + + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("Expecting numeric lease time"); + skip_to_semi (cfile); + return; + } + convert_num ((unsigned char *)timep, val, 10, 32); + /* Unswap the number - convert_num returns stuff in NBO. */ + *timep = ntohl (*timep); /* XXX */ + + parse_semi (cfile); +} + +/* No BNF for numeric aggregates - that's defined by the caller. What + this function does is to parse a sequence of numbers seperated by + the token specified in seperator. If max is zero, any number of + numbers will be parsed; otherwise, exactly max numbers are + expected. Base and size tell us how to internalize the numbers + once they've been tokenized. */ + +unsigned char *parse_numeric_aggregate (cfile, buf, + max, seperator, base, size) + FILE *cfile; + unsigned char *buf; + int *max; + int seperator; + int base; + int size; +{ + char *val; + int token; + unsigned char *bufp = buf, *s; + char *t; + int count = 0; + pair c = (pair)0; + + if (!bufp && *max) { + bufp = (unsigned char *)malloc (*max * size / 8); + if (!bufp) + error ("can't allocate space for numeric aggregate"); + } else + s = bufp; + + do { + if (count) { + token = peek_token (&val, cfile); + if (token != seperator) { + if (!*max) + break; + if (token != RBRACE && token != LBRACE) + token = next_token (&val, cfile); + parse_warn ("too few numbers."); + if (token != SEMI) + skip_to_semi (cfile); + return (unsigned char *)0; + } + token = next_token (&val, cfile); + } + token = next_token (&val, cfile); + + if (token == EOF) { + parse_warn ("unexpected end of file"); + break; + } + + /* Allow NUMBER_OR_NAME if base is 16. */ + if (token != NUMBER && + (base != 16 || token != NUMBER_OR_NAME)) { + parse_warn ("expecting numeric value."); + skip_to_semi (cfile); + return (unsigned char *)0; + } + /* If we can, convert the number now; otherwise, build + a linked list of all the numbers. */ + if (s) { + convert_num (s, val, base, size); + s += size / 8; + } else { + t = (char *)malloc (strlen (val) + 1); + if (!t) + error ("no temp space for number."); + strcpy (t, val); + c = cons (t, c); + } + } while (++count != *max); + + /* If we had to cons up a list, convert it now. */ + if (c) { + bufp = (unsigned char *)malloc (count * size / 8); + if (!bufp) + error ("can't allocate space for numeric aggregate."); + s = bufp + count - size / 8; + *max = count; + } + while (c) { + pair cdr = c -> cdr; + convert_num (s, (char *)(c -> car), base, size); + s -= size / 8; + /* Free up temp space. */ + free (c -> car); + free (c); + c = cdr; + } + return bufp; +} + +void convert_num (buf, str, base, size) + unsigned char *buf; + char *str; + int base; + int size; +{ + char *ptr = str; + int negative = 0; + u_int32_t val = 0; + int tval; + int max; + + if (*ptr == '-') { + negative = 1; + ++ptr; + } + + /* If base wasn't specified, figure it out from the data. */ + if (!base) { + if (ptr [0] == '0') { + if (ptr [1] == 'x') { + base = 16; + ptr += 2; + } else if (isascii (ptr [1]) && isdigit (ptr [1])) { + base = 8; + ptr += 1; + } else { + base = 10; + } + } else { + base = 10; + } + } + + do { + tval = *ptr++; + /* XXX assumes ASCII... */ + if (tval >= 'a') + tval = tval - 'a' + 10; + else if (tval >= 'A') + tval = tval - 'A' + 10; + else if (tval >= '0') + tval -= '0'; + else { + warn ("Bogus number: %s.", str); + break; + } + if (tval >= base) { + warn ("Bogus number: %s: digit %d not in base %d\n", + str, tval, base); + break; + } + val = val * base + tval; + } while (*ptr); + + if (negative) + max = (1 << (size - 1)); + else + max = (1 << (size - 1)) + ((1 << (size - 1)) - 1); + if (val > max) { + switch (base) { + case 8: + warn ("value %s%o exceeds max (%d) for precision.", + negative ? "-" : "", val, max); + break; + case 16: + warn ("value %s%x exceeds max (%d) for precision.", + negative ? "-" : "", val, max); + break; + default: + warn ("value %s%u exceeds max (%d) for precision.", + negative ? "-" : "", val, max); + break; + } + } + + if (negative) { + switch (size) { + case 8: + *buf = -(unsigned long)val; + break; + case 16: + putShort (buf, -(unsigned long)val); + break; + case 32: + putLong (buf, -(unsigned long)val); + break; + default: + warn ("Unexpected integer size: %d\n", size); + break; + } + } else { + switch (size) { + case 8: + *buf = (u_int8_t)val; + break; + case 16: + putUShort (buf, (u_int16_t)val); + break; + case 32: + putULong (buf, val); + break; + default: + warn ("Unexpected integer size: %d\n", size); + break; + } + } +} + +/* date :== NUMBER NUMBER SLASH NUMBER SLASH NUMBER + NUMBER COLON NUMBER COLON NUMBER SEMI + + Dates are always in GMT; first number is day of week; next is + year/month/day; next is hours:minutes:seconds on a 24-hour + clock. */ + +TIME parse_date (cfile) + FILE *cfile; +{ + struct tm tm; + int guess; + char *val; + int token; + static int months [11] = { 31, 59, 90, 120, 151, 181, + 212, 243, 273, 304, 334 }; + + /* Day of week... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric day of week expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_wday = atoi (val); + + /* Year... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric year expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_year = atoi (val); + if (tm.tm_year > 1900) + tm.tm_year -= 1900; + + /* Slash seperating year from month... */ + token = next_token (&val, cfile); + if (token != SLASH) { + parse_warn ("expected slash seperating year from month."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + + /* Month... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric month expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_mon = atoi (val) - 1; + + /* Slash seperating month from day... */ + token = next_token (&val, cfile); + if (token != SLASH) { + parse_warn ("expected slash seperating month from day."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + + /* Month... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric day of month expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_mday = atoi (val); + + /* Hour... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric hour expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_hour = atoi (val); + + /* Colon seperating hour from minute... */ + token = next_token (&val, cfile); + if (token != COLON) { + parse_warn ("expected colon seperating hour from minute."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + + /* Minute... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric minute expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_min = atoi (val); + + /* Colon seperating minute from second... */ + token = next_token (&val, cfile); + if (token != COLON) { + parse_warn ("expected colon seperating hour from minute."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + + /* Minute... */ + token = next_token (&val, cfile); + if (token != NUMBER) { + parse_warn ("numeric minute expected."); + if (token != SEMI) + skip_to_semi (cfile); + return (TIME)0; + } + tm.tm_sec = atoi (val); + tm.tm_isdst = 0; + + /* XXX */ /* We assume that mktime does not use tm_yday. */ + tm.tm_yday = 0; + + /* Make sure the date ends in a semicolon... */ + token = next_token (&val, cfile); + if (token != SEMI) { + parse_warn ("semicolon expected."); + skip_to_semi (cfile); + return 0; + } + + /* Guess the time value... */ + guess = ((((((365 * (tm.tm_year - 70) + /* Days in years since '70 */ + (tm.tm_year - 69) / 4 + /* Leap days since '70 */ + (tm.tm_mon /* Days in months this year */ + ? months [tm.tm_mon - 1] + : 0) + + (tm.tm_mon > 1 && /* Leap day this year */ + !((tm.tm_year - 72) & 3)) + + tm.tm_mday - 1) * 24) + /* Day of month */ + tm.tm_hour) * 60) + + tm.tm_min) * 60) + tm.tm_sec; + + /* This guess could be wrong because of leap seconds or other + weirdness we don't know about that the system does. For + now, we're just going to accept the guess, but at some point + it might be nice to do a successive approximation here to + get an exact value. Even if the error is small, if the + server is restarted frequently (and thus the lease database + is reread), the error could accumulate into something + significant. */ + + return guess; +} diff --git a/contrib/isc-dhcp/common/print.c b/contrib/isc-dhcp/common/print.c new file mode 100644 index 0000000..ed51b15 --- /dev/null +++ b/contrib/isc-dhcp/common/print.c @@ -0,0 +1,184 @@ +/* print.c + + Turn data structures into printable text. */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: print.c,v 1.16.2.1 1998/06/25 21:11:31 mellon Exp $ Copyright (c) 1995, 1996, 1997, 1998 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +char *print_hw_addr (htype, hlen, data) + int htype; + int hlen; + unsigned char *data; +{ + static char habuf [49]; + char *s; + int i; + + if (htype == 0 || hlen == 0) { + strcpy (habuf, "<null>"); + } else { + s = habuf; + for (i = 0; i < hlen; i++) { + sprintf (s, "%02x", data [i]); + s += strlen (s); + *s++ = ':'; + } + *--s = 0; + } + return habuf; +} + +void print_lease (lease) + struct lease *lease; +{ + struct tm *t; + char tbuf [32]; + + debug (" Lease %s", + piaddr (lease -> ip_addr)); + + t = gmtime (&lease -> starts); + strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t); + debug (" start %s", tbuf); + + t = gmtime (&lease -> ends); + strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t); + debug (" end %s", tbuf); + + t = gmtime (&lease -> timestamp); + strftime (tbuf, sizeof tbuf, "%D %H:%M:%S", t); + debug (" stamp %s", tbuf); + + debug (" hardware addr = %s", + print_hw_addr (lease -> hardware_addr.htype, + lease -> hardware_addr.hlen, + lease -> hardware_addr.haddr)); + debug (" host %s ", + lease -> host ? lease -> host -> name : "<none>"); +} + +void dump_packet (tp) + struct packet *tp; +{ + struct dhcp_packet *tdp = tp -> raw; + + debug ("packet length %d", tp -> packet_length); + debug ("op = %d htype = %d hlen = %d hops = %d", + tdp -> op, tdp -> htype, tdp -> hlen, tdp -> hops); + debug ("xid = %x secs = %d flags = %x", + tdp -> xid, tdp -> secs, tdp -> flags); + debug ("ciaddr = %s", inet_ntoa (tdp -> ciaddr)); + debug ("yiaddr = %s", inet_ntoa (tdp -> yiaddr)); + debug ("siaddr = %s", inet_ntoa (tdp -> siaddr)); + debug ("giaddr = %s", inet_ntoa (tdp -> giaddr)); + debug ("chaddr = %02.2x:%02.2x:%02.2x:%02.2x:%02.2x:%02.2x", + ((unsigned char *)(tdp -> chaddr)) [0], + ((unsigned char *)(tdp -> chaddr)) [1], + ((unsigned char *)(tdp -> chaddr)) [2], + ((unsigned char *)(tdp -> chaddr)) [3], + ((unsigned char *)(tdp -> chaddr)) [4], + ((unsigned char *)(tdp -> chaddr)) [5]); + debug ("filename = %s", tdp -> file); + debug ("server_name = %s", tdp -> sname); + if (tp -> options_valid) { + int i; + + for (i = 0; i < 256; i++) { + if (tp -> options [i].data) + debug (" %s = %s", + dhcp_options [i].name, + pretty_print_option + (i, tp -> options [i].data, + tp -> options [i].len, 1, 1)); + } + } + debug (""); +} + +void dump_raw (buf, len) + unsigned char *buf; + int len; +{ + int i; + char lbuf [80]; + int lbix = 0; + + lbuf [0] = 0; + + for (i = 0; i < len; i++) { + if ((i & 15) == 0) { + if (lbix) + note (lbuf); + sprintf (lbuf, "%03x:", i); + lbix = 4; + } else if ((i & 7) == 0) + lbuf [lbix++] = ' '; + sprintf (&lbuf [lbix], " %02x", buf [i]); + lbix += 3; + } + note (lbuf); +} + +void hash_dump (table) + struct hash_table *table; +{ + int i; + struct hash_bucket *bp; + + if (!table) + return; + + for (i = 0; i < table -> hash_count; i++) { + if (!table -> buckets [i]) + continue; + note ("hash bucket %d:", i); + for (bp = table -> buckets [i]; bp; bp = bp -> next) { + if (bp -> len) + dump_raw (bp -> name, bp -> len); + else + note ((char *)bp -> name); + } + } +} diff --git a/contrib/isc-dhcp/common/raw.c b/contrib/isc-dhcp/common/raw.c new file mode 100644 index 0000000..973ede1 --- /dev/null +++ b/contrib/isc-dhcp/common/raw.c @@ -0,0 +1,132 @@ +/* socket.c + + BSD raw socket interface code... */ + +/* XXX + + It's not clear how this should work, and that lack of clarity is + terribly detrimental to the NetBSD 1.1 kernel - it crashes and + burns. + + Using raw sockets ought to be a big win over using BPF or something + like it, because you don't need to deal with the complexities of + the physical layer, but it appears not to be possible with existing + raw socket implementations. This may be worth revisiting in the + future. For now, this code can probably be considered a curiosity. + Sigh. */ + +/* + * 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''. */ + +#ifndef lint +static char copyright[] = +"$Id: raw.c,v 1.11 1997/10/20 21:47:14 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#if defined (USE_RAW_SEND) +#include <sys/uio.h> + +/* Generic interface registration routine... */ +void if_register_send (info) + struct interface_info *info; +{ + struct sockaddr_in name; + int sock; + struct socklist *tmp; + int flag; + + /* Set up the address we're going to connect to. */ + name.sin_family = AF_INET; + name.sin_port = local_port; + name.sin_addr.s_addr = htonl (INADDR_BROADCAST); + memset (name.sin_zero, 0, sizeof (name.sin_zero)); + + /* List addresses on which we're listening. */ + if (!quiet_interface_discovery) + note ("Sending on %s, port %d", + piaddr (info -> address), htons (local_port)); + if ((sock = socket (AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) + error ("Can't create dhcp socket: %m"); + + /* Set the BROADCAST option so that we can broadcast DHCP responses. */ + flag = 1; + if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, + &flag, sizeof flag) < 0) + error ("Can't set SO_BROADCAST option on dhcp socket: %m"); + + /* Set the IP_HDRINCL flag so that we can supply our own IP + headers... */ + if (setsockopt (sock, IPPROTO_IP, IP_HDRINCL, &flag, sizeof flag) < 0) + error ("Can't set IP_HDRINCL flag: %m"); + + info -> wfdesc = sock; + if (!quiet_interface_discovery) + note ("Sending on Raw/%s/%s", + info -> name, + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} + +size_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + unsigned char buf [256]; + int bufp = 0; + struct iovec iov [2]; + + /* Assemble the headers... */ + assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + to -> sin_addr.s_addr, to -> sin_port, + (unsigned char *)raw, len); + + /* Fire it off */ + iov [0].iov_base = (char *)buf; + iov [0].iov_len = bufp; + iov [1].iov_base = (char *)raw; + iov [1].iov_len = len; + + return writev(interface -> wfdesc, iov, 2); +} +#endif /* USE_SOCKET_SEND */ diff --git a/contrib/isc-dhcp/common/socket.c b/contrib/isc-dhcp/common/socket.c new file mode 100644 index 0000000..b317ff2 --- /dev/null +++ b/contrib/isc-dhcp/common/socket.c @@ -0,0 +1,256 @@ +/* socket.c + + BSD socket interface code... */ + +/* + * 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''. + */ + +/* SO_BINDTODEVICE support added by Elliot Poger (poger@leland.stanford.edu). + * This sockopt allows a socket to be bound to a particular interface, + * thus enabling the use of DHCPD on a multihomed host. + * If SO_BINDTODEVICE is defined in your system header files, the use of + * this sockopt will be automatically enabled. + * I have implemented it under Linux; other systems should be doable also. + */ + +#ifndef lint +static char copyright[] = +"$Id: socket.c,v 1.26.2.2 1998/06/25 21:11:32 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +#ifdef USE_SOCKET_FALLBACK +# define USE_SOCKET_SEND +# define if_register_send if_register_fallback +# define send_packet send_fallback +# define if_reinitialize_send if_reinitialize_fallback +#endif + +static int once = 0; + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_SOCKET_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +#if 0 +#ifndef USE_SOCKET_RECEIVE + once = 0; + close (info -> wfdesc); +#endif + if_register_send (info); +#endif +} +#endif + +#ifdef USE_SOCKET_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +#if 0 + once = 0; + close (info -> rfdesc); + if_register_receive (info); +#endif +} +#endif + +#if defined (USE_SOCKET_SEND) || defined (USE_SOCKET_RECEIVE) +/* Generic interface registration routine... */ +int if_register_socket (info) + struct interface_info *info; +{ + struct sockaddr_in name; + int sock; + int flag; + +#ifndef SO_BINDTODEVICE + /* Make sure only one interface is registered. */ + if (once) + error ("The standard socket API can only support %s", + "hosts with a single network interface."); + once = 1; +#endif + + /* Set up the address we're going to bind to. */ + name.sin_family = AF_INET; + name.sin_port = local_port; + name.sin_addr.s_addr = INADDR_ANY; + memset (name.sin_zero, 0, sizeof (name.sin_zero)); + + /* Make a socket... */ + if ((sock = socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) + error ("Can't create dhcp socket: %m"); + + /* Set the REUSEADDR option so that we don't fail to start if + we're being restarted. */ + flag = 1; + if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, + (char *)&flag, sizeof flag) < 0) + error ("Can't set SO_REUSEADDR option on dhcp socket: %m"); + + /* Set the BROADCAST option so that we can broadcast DHCP responses. */ + if (setsockopt (sock, SOL_SOCKET, SO_BROADCAST, + (char *)&flag, sizeof flag) < 0) + error ("Can't set SO_BROADCAST option on dhcp socket: %m"); + + /* Bind the socket to this interface's IP address. */ + if (bind (sock, (struct sockaddr *)&name, sizeof name) < 0) + error ("Can't bind to dhcp address: %m"); + +#ifdef SO_BINDTODEVICE + /* Bind this socket to this interface. */ + if (setsockopt (sock, SOL_SOCKET, SO_BINDTODEVICE, + (char *)(info -> ifp), sizeof *(info -> ifp)) < 0) { + error("setting SO_BINDTODEVICE"); + } +#endif + + return sock; +} +#endif /* USE_SOCKET_SEND || USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_SEND +void if_register_send (info) + struct interface_info *info; +{ +#ifndef USE_SOCKET_RECEIVE + info -> wfdesc = if_register_socket (info); +#else + info -> wfdesc = info -> rfdesc; +#endif + if (!quiet_interface_discovery) + note ("Sending on Socket/%s/%s", + info -> name, + (info -> shared_network ? + info -> shared_network -> name : "unattached")); + +} +#endif /* USE_SOCKET_SEND */ + +#ifdef USE_SOCKET_RECEIVE +void if_register_receive (info) + struct interface_info *info; +{ + /* If we're using the socket API for sending and receiving, + we don't need to register this interface twice. */ + info -> rfdesc = if_register_socket (info); + if (!quiet_interface_discovery) + note ("Listening on Socket/%s/%s", + info -> name, + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + int result; +#ifdef IGNORE_HOSTUNREACH + int retry = 0; + do { +#endif + result = sendto (interface -> wfdesc, (char *)raw, len, 0, + (struct sockaddr *)to, sizeof *to); +#ifdef IGNORE_HOSTUNREACH + } while (to -> sin_addr.s_addr == htonl (INADDR_BROADCAST) && + result < 0 && + (errno == EHOSTUNREACH || + errno == ECONNREFUSED) && + retry++ < 10); +#endif + return result; +} +#endif /* USE_SOCKET_SEND */ + +#ifdef USE_SOCKET_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + int flen = sizeof *from; + int result; + +#ifdef IGNORE_HOSTUNREACH + int retry = 0; + do { +#endif + result = recvfrom (interface -> rfdesc, (char *)buf, len, 0, + (struct sockaddr *)from, &flen); +#ifdef IGNORE_HOSTUNREACH + } while (result < 0 && + (errno == EHOSTUNREACH || + errno == ECONNREFUSED) && + retry++ < 10); +#endif + return result; +} +#endif /* USE_SOCKET_RECEIVE */ + +#ifdef USE_SOCKET_FALLBACK +/* This just reads in a packet and silently discards it. */ + +void fallback_discard (protocol) + struct protocol *protocol; +{ + char buf [1540]; + struct sockaddr_in from; + int flen = sizeof from; + int status; + struct interface_info *interface = protocol -> local; + + status = recvfrom (interface -> wfdesc, buf, sizeof buf, 0, + (struct sockaddr *)&from, &flen); + if (status < 0) + warn ("fallback_discard: %m"); +} +#endif /* USE_SOCKET_RECEIVE */ diff --git a/contrib/isc-dhcp/common/tables.c b/contrib/isc-dhcp/common/tables.c new file mode 100644 index 0000000..bdbba1b --- /dev/null +++ b/contrib/isc-dhcp/common/tables.c @@ -0,0 +1,692 @@ +/* tables.c + + Tables of information... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: tables.c,v 1.13.2.1 1998/06/25 21:11:32 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +/* 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 signed integer + S - 16-bit unsigned integer + b - 8-bit signed 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) +*/ + +struct universe dhcp_universe; +struct option dhcp_options [256] = { + { "pad", "", &dhcp_universe, 0 }, + { "subnet-mask", "I", &dhcp_universe, 1 }, + { "time-offset", "l", &dhcp_universe, 2 }, + { "routers", "IA", &dhcp_universe, 3 }, + { "time-servers", "IA", &dhcp_universe, 4 }, + { "ien116-name-servers", "IA", &dhcp_universe, 5 }, + { "domain-name-servers", "IA", &dhcp_universe, 6 }, + { "log-servers", "IA", &dhcp_universe, 7 }, + { "cookie-servers", "IA", &dhcp_universe, 8 }, + { "lpr-servers", "IA", &dhcp_universe, 9 }, + { "impress-servers", "IA", &dhcp_universe, 10 }, + { "resource-location-servers", "IA", &dhcp_universe, 11 }, + { "host-name", "t", &dhcp_universe, 12 }, + { "boot-size", "S", &dhcp_universe, 13 }, + { "merit-dump", "t", &dhcp_universe, 14 }, + { "domain-name", "t", &dhcp_universe, 15 }, + { "swap-server", "I", &dhcp_universe, 16 }, + { "root-path", "t", &dhcp_universe, 17 }, + { "extensions-path", "t", &dhcp_universe, 18 }, + { "ip-forwarding", "f", &dhcp_universe, 19 }, + { "non-local-source-routing", "f", &dhcp_universe, 20 }, + { "policy-filter", "IIA", &dhcp_universe, 21 }, + { "max-dgram-reassembly", "S", &dhcp_universe, 22 }, + { "default-ip-ttl", "B", &dhcp_universe, 23 }, + { "path-mtu-aging-timeout", "L", &dhcp_universe, 24 }, + { "path-mtu-plateau-table", "SA", &dhcp_universe, 25 }, + { "interface-mtu", "S", &dhcp_universe, 26 }, + { "all-subnets-local", "f", &dhcp_universe, 27 }, + { "broadcast-address", "I", &dhcp_universe, 28 }, + { "perform-mask-discovery", "f", &dhcp_universe, 29 }, + { "mask-supplier", "f", &dhcp_universe, 30 }, + { "router-discovery", "f", &dhcp_universe, 31 }, + { "router-solicitation-address", "I", &dhcp_universe, 32 }, + { "static-routes", "IIA", &dhcp_universe, 33 }, + { "trailer-encapsulation", "f", &dhcp_universe, 34 }, + { "arp-cache-timeout", "L", &dhcp_universe, 35 }, + { "ieee802-3-encapsulation", "f", &dhcp_universe, 36 }, + { "default-tcp-ttl", "B", &dhcp_universe, 37 }, + { "tcp-keepalive-interval", "L", &dhcp_universe, 38 }, + { "tcp-keepalive-garbage", "f", &dhcp_universe, 39 }, + { "nis-domain", "t", &dhcp_universe, 40 }, + { "nis-servers", "IA", &dhcp_universe, 41 }, + { "ntp-servers", "IA", &dhcp_universe, 42 }, + { "vendor-encapsulated-options", "X", &dhcp_universe, 43 }, + { "netbios-name-servers", "IA", &dhcp_universe, 44 }, + { "netbios-dd-server", "IA", &dhcp_universe, 45 }, + { "netbios-node-type", "B", &dhcp_universe, 46 }, + { "netbios-scope", "t", &dhcp_universe, 47 }, + { "font-servers", "IA", &dhcp_universe, 48 }, + { "x-display-manager", "IA", &dhcp_universe, 49 }, + { "dhcp-requested-address", "I", &dhcp_universe, 50 }, + { "dhcp-lease-time", "L", &dhcp_universe, 51 }, + { "dhcp-option-overload", "B", &dhcp_universe, 52 }, + { "dhcp-message-type", "B", &dhcp_universe, 53 }, + { "dhcp-server-identifier", "I", &dhcp_universe, 54 }, + { "dhcp-parameter-request-list", "BA", &dhcp_universe, 55 }, + { "dhcp-message", "t", &dhcp_universe, 56 }, + { "dhcp-max-message-size", "S", &dhcp_universe, 57 }, + { "dhcp-renewal-time", "L", &dhcp_universe, 58 }, + { "dhcp-rebinding-time", "L", &dhcp_universe, 59 }, + { "dhcp-class-identifier", "t", &dhcp_universe, 60 }, + { "dhcp-client-identifier", "X", &dhcp_universe, 61 }, + { "option-62", "X", &dhcp_universe, 62 }, + { "option-63", "X", &dhcp_universe, 63 }, + { "option-64", "X", &dhcp_universe, 64 }, + { "option-65", "X", &dhcp_universe, 65 }, + { "option-66", "X", &dhcp_universe, 66 }, + { "option-67", "X", &dhcp_universe, 67 }, + { "option-68", "X", &dhcp_universe, 68 }, + { "option-69", "X", &dhcp_universe, 69 }, + { "option-70", "X", &dhcp_universe, 70 }, + { "option-71", "X", &dhcp_universe, 71 }, + { "option-72", "X", &dhcp_universe, 72 }, + { "option-73", "X", &dhcp_universe, 73 }, + { "option-74", "X", &dhcp_universe, 74 }, + { "option-75", "X", &dhcp_universe, 75 }, + { "option-76", "X", &dhcp_universe, 76 }, + { "dhcp-user-class-identifier", "t", &dhcp_universe, 77 }, + { "option-78", "X", &dhcp_universe, 78 }, + { "option-79", "X", &dhcp_universe, 79 }, + { "option-80", "X", &dhcp_universe, 80 }, + { "option-81", "X", &dhcp_universe, 81 }, + { "option-82", "X", &dhcp_universe, 82 }, + { "option-83", "X", &dhcp_universe, 83 }, + { "option-84", "X", &dhcp_universe, 84 }, + { "nds-servers", "IA", &dhcp_universe, 85 }, + { "nds-tree-name", "X", &dhcp_universe, 86 }, + { "nds-context", "X", &dhcp_universe, 87 }, + { "option-88", "X", &dhcp_universe, 88 }, + { "option-89", "X", &dhcp_universe, 89 }, + { "option-90", "X", &dhcp_universe, 90 }, + { "option-91", "X", &dhcp_universe, 91 }, + { "option-92", "X", &dhcp_universe, 92 }, + { "option-93", "X", &dhcp_universe, 93 }, + { "option-94", "X", &dhcp_universe, 94 }, + { "option-95", "X", &dhcp_universe, 95 }, + { "option-96", "X", &dhcp_universe, 96 }, + { "option-97", "X", &dhcp_universe, 97 }, + { "option-98", "X", &dhcp_universe, 98 }, + { "option-99", "X", &dhcp_universe, 99 }, + { "option-100", "X", &dhcp_universe, 100 }, + { "option-101", "X", &dhcp_universe, 101 }, + { "option-102", "X", &dhcp_universe, 102 }, + { "option-103", "X", &dhcp_universe, 103 }, + { "option-104", "X", &dhcp_universe, 104 }, + { "option-105", "X", &dhcp_universe, 105 }, + { "option-106", "X", &dhcp_universe, 106 }, + { "option-107", "X", &dhcp_universe, 107 }, + { "option-108", "X", &dhcp_universe, 108 }, + { "option-109", "X", &dhcp_universe, 109 }, + { "option-110", "X", &dhcp_universe, 110 }, + { "option-111", "X", &dhcp_universe, 111 }, + { "option-112", "X", &dhcp_universe, 112 }, + { "option-113", "X", &dhcp_universe, 113 }, + { "option-114", "X", &dhcp_universe, 114 }, + { "option-115", "X", &dhcp_universe, 115 }, + { "option-116", "X", &dhcp_universe, 116 }, + { "option-117", "X", &dhcp_universe, 117 }, + { "option-118", "X", &dhcp_universe, 118 }, + { "option-119", "X", &dhcp_universe, 119 }, + { "option-120", "X", &dhcp_universe, 120 }, + { "option-121", "X", &dhcp_universe, 121 }, + { "option-122", "X", &dhcp_universe, 122 }, + { "option-123", "X", &dhcp_universe, 123 }, + { "option-124", "X", &dhcp_universe, 124 }, + { "option-125", "X", &dhcp_universe, 125 }, + { "option-126", "X", &dhcp_universe, 126 }, + { "option-127", "X", &dhcp_universe, 127 }, + { "option-128", "X", &dhcp_universe, 128 }, + { "option-129", "X", &dhcp_universe, 129 }, + { "option-130", "X", &dhcp_universe, 130 }, + { "option-131", "X", &dhcp_universe, 131 }, + { "option-132", "X", &dhcp_universe, 132 }, + { "option-133", "X", &dhcp_universe, 133 }, + { "option-134", "X", &dhcp_universe, 134 }, + { "option-135", "X", &dhcp_universe, 135 }, + { "option-136", "X", &dhcp_universe, 136 }, + { "option-137", "X", &dhcp_universe, 137 }, + { "option-138", "X", &dhcp_universe, 138 }, + { "option-139", "X", &dhcp_universe, 139 }, + { "option-140", "X", &dhcp_universe, 140 }, + { "option-141", "X", &dhcp_universe, 141 }, + { "option-142", "X", &dhcp_universe, 142 }, + { "option-143", "X", &dhcp_universe, 143 }, + { "option-144", "X", &dhcp_universe, 144 }, + { "option-145", "X", &dhcp_universe, 145 }, + { "option-146", "X", &dhcp_universe, 146 }, + { "option-147", "X", &dhcp_universe, 147 }, + { "option-148", "X", &dhcp_universe, 148 }, + { "option-149", "X", &dhcp_universe, 149 }, + { "option-150", "X", &dhcp_universe, 150 }, + { "option-151", "X", &dhcp_universe, 151 }, + { "option-152", "X", &dhcp_universe, 152 }, + { "option-153", "X", &dhcp_universe, 153 }, + { "option-154", "X", &dhcp_universe, 154 }, + { "option-155", "X", &dhcp_universe, 155 }, + { "option-156", "X", &dhcp_universe, 156 }, + { "option-157", "X", &dhcp_universe, 157 }, + { "option-158", "X", &dhcp_universe, 158 }, + { "option-159", "X", &dhcp_universe, 159 }, + { "option-160", "X", &dhcp_universe, 160 }, + { "option-161", "X", &dhcp_universe, 161 }, + { "option-162", "X", &dhcp_universe, 162 }, + { "option-163", "X", &dhcp_universe, 163 }, + { "option-164", "X", &dhcp_universe, 164 }, + { "option-165", "X", &dhcp_universe, 165 }, + { "option-166", "X", &dhcp_universe, 166 }, + { "option-167", "X", &dhcp_universe, 167 }, + { "option-168", "X", &dhcp_universe, 168 }, + { "option-169", "X", &dhcp_universe, 169 }, + { "option-170", "X", &dhcp_universe, 170 }, + { "option-171", "X", &dhcp_universe, 171 }, + { "option-172", "X", &dhcp_universe, 172 }, + { "option-173", "X", &dhcp_universe, 173 }, + { "option-174", "X", &dhcp_universe, 174 }, + { "option-175", "X", &dhcp_universe, 175 }, + { "option-176", "X", &dhcp_universe, 176 }, + { "option-177", "X", &dhcp_universe, 177 }, + { "option-178", "X", &dhcp_universe, 178 }, + { "option-179", "X", &dhcp_universe, 179 }, + { "option-180", "X", &dhcp_universe, 180 }, + { "option-181", "X", &dhcp_universe, 181 }, + { "option-182", "X", &dhcp_universe, 182 }, + { "option-183", "X", &dhcp_universe, 183 }, + { "option-184", "X", &dhcp_universe, 184 }, + { "option-185", "X", &dhcp_universe, 185 }, + { "option-186", "X", &dhcp_universe, 186 }, + { "option-187", "X", &dhcp_universe, 187 }, + { "option-188", "X", &dhcp_universe, 188 }, + { "option-189", "X", &dhcp_universe, 189 }, + { "option-190", "X", &dhcp_universe, 190 }, + { "option-191", "X", &dhcp_universe, 191 }, + { "option-192", "X", &dhcp_universe, 192 }, + { "option-193", "X", &dhcp_universe, 193 }, + { "option-194", "X", &dhcp_universe, 194 }, + { "option-195", "X", &dhcp_universe, 195 }, + { "option-196", "X", &dhcp_universe, 196 }, + { "option-197", "X", &dhcp_universe, 197 }, + { "option-198", "X", &dhcp_universe, 198 }, + { "option-199", "X", &dhcp_universe, 199 }, + { "option-200", "X", &dhcp_universe, 200 }, + { "option-201", "X", &dhcp_universe, 201 }, + { "option-202", "X", &dhcp_universe, 202 }, + { "option-203", "X", &dhcp_universe, 203 }, + { "option-204", "X", &dhcp_universe, 204 }, + { "option-205", "X", &dhcp_universe, 205 }, + { "option-206", "X", &dhcp_universe, 206 }, + { "option-207", "X", &dhcp_universe, 207 }, + { "option-208", "X", &dhcp_universe, 208 }, + { "option-209", "X", &dhcp_universe, 209 }, + { "option-210", "X", &dhcp_universe, 210 }, + { "option-211", "X", &dhcp_universe, 211 }, + { "option-212", "X", &dhcp_universe, 212 }, + { "option-213", "X", &dhcp_universe, 213 }, + { "option-214", "X", &dhcp_universe, 214 }, + { "option-215", "X", &dhcp_universe, 215 }, + { "option-216", "X", &dhcp_universe, 216 }, + { "option-217", "X", &dhcp_universe, 217 }, + { "option-218", "X", &dhcp_universe, 218 }, + { "option-219", "X", &dhcp_universe, 219 }, + { "option-220", "X", &dhcp_universe, 220 }, + { "option-221", "X", &dhcp_universe, 221 }, + { "option-222", "X", &dhcp_universe, 222 }, + { "option-223", "X", &dhcp_universe, 223 }, + { "option-224", "X", &dhcp_universe, 224 }, + { "option-225", "X", &dhcp_universe, 225 }, + { "option-226", "X", &dhcp_universe, 226 }, + { "option-227", "X", &dhcp_universe, 227 }, + { "option-228", "X", &dhcp_universe, 228 }, + { "option-229", "X", &dhcp_universe, 229 }, + { "option-230", "X", &dhcp_universe, 230 }, + { "option-231", "X", &dhcp_universe, 231 }, + { "option-232", "X", &dhcp_universe, 232 }, + { "option-233", "X", &dhcp_universe, 233 }, + { "option-234", "X", &dhcp_universe, 234 }, + { "option-235", "X", &dhcp_universe, 235 }, + { "option-236", "X", &dhcp_universe, 236 }, + { "option-237", "X", &dhcp_universe, 237 }, + { "option-238", "X", &dhcp_universe, 238 }, + { "option-239", "X", &dhcp_universe, 239 }, + { "option-240", "X", &dhcp_universe, 240 }, + { "option-241", "X", &dhcp_universe, 241 }, + { "option-242", "X", &dhcp_universe, 242 }, + { "option-243", "X", &dhcp_universe, 243 }, + { "option-244", "X", &dhcp_universe, 244 }, + { "option-245", "X", &dhcp_universe, 245 }, + { "option-246", "X", &dhcp_universe, 246 }, + { "option-247", "X", &dhcp_universe, 247 }, + { "option-248", "X", &dhcp_universe, 248 }, + { "option-249", "X", &dhcp_universe, 249 }, + { "option-250", "X", &dhcp_universe, 250 }, + { "option-251", "X", &dhcp_universe, 251 }, + { "option-252", "X", &dhcp_universe, 252 }, + { "option-253", "X", &dhcp_universe, 253 }, + { "option-254", "X", &dhcp_universe, 254 }, + { "option-end", "e", &dhcp_universe, 255 }, +}; + +/* Default dhcp option priority list (this is ad hoc and should not be + mistaken for a carefully crafted and optimized list). */ +unsigned char dhcp_option_default_priority_list [] = { + DHO_DHCP_REQUESTED_ADDRESS, + DHO_DHCP_OPTION_OVERLOAD, + DHO_DHCP_MAX_MESSAGE_SIZE, + DHO_DHCP_RENEWAL_TIME, + DHO_DHCP_REBINDING_TIME, + DHO_DHCP_CLASS_IDENTIFIER, + DHO_DHCP_CLIENT_IDENTIFIER, + DHO_SUBNET_MASK, + DHO_TIME_OFFSET, + DHO_ROUTERS, + DHO_TIME_SERVERS, + DHO_NAME_SERVERS, + DHO_DOMAIN_NAME_SERVERS, + DHO_HOST_NAME, + DHO_LOG_SERVERS, + DHO_COOKIE_SERVERS, + DHO_LPR_SERVERS, + DHO_IMPRESS_SERVERS, + DHO_RESOURCE_LOCATION_SERVERS, + DHO_HOST_NAME, + DHO_BOOT_SIZE, + DHO_MERIT_DUMP, + DHO_DOMAIN_NAME, + DHO_SWAP_SERVER, + DHO_ROOT_PATH, + DHO_EXTENSIONS_PATH, + DHO_IP_FORWARDING, + DHO_NON_LOCAL_SOURCE_ROUTING, + DHO_POLICY_FILTER, + DHO_MAX_DGRAM_REASSEMBLY, + DHO_DEFAULT_IP_TTL, + DHO_PATH_MTU_AGING_TIMEOUT, + DHO_PATH_MTU_PLATEAU_TABLE, + DHO_INTERFACE_MTU, + DHO_ALL_SUBNETS_LOCAL, + DHO_BROADCAST_ADDRESS, + DHO_PERFORM_MASK_DISCOVERY, + DHO_MASK_SUPPLIER, + DHO_ROUTER_DISCOVERY, + DHO_ROUTER_SOLICITATION_ADDRESS, + DHO_STATIC_ROUTES, + DHO_TRAILER_ENCAPSULATION, + DHO_ARP_CACHE_TIMEOUT, + DHO_IEEE802_3_ENCAPSULATION, + DHO_DEFAULT_TCP_TTL, + DHO_TCP_KEEPALIVE_INTERVAL, + DHO_TCP_KEEPALIVE_GARBAGE, + DHO_NIS_DOMAIN, + DHO_NIS_SERVERS, + DHO_NTP_SERVERS, + DHO_VENDOR_ENCAPSULATED_OPTIONS, + DHO_NETBIOS_NAME_SERVERS, + DHO_NETBIOS_DD_SERVER, + DHO_NETBIOS_NODE_TYPE, + DHO_NETBIOS_SCOPE, + DHO_FONT_SERVERS, + DHO_X_DISPLAY_MANAGER, + DHO_DHCP_PARAMETER_REQUEST_LIST, + + /* Presently-undefined options... */ + 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, + 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, + 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, + 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, + 143, 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, + 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 166, + 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, + 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, + 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, + 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, + 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, + 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, + 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, + 251, 252, 253, 254, +}; + +int sizeof_dhcp_option_default_priority_list = + sizeof dhcp_option_default_priority_list; + + +char *hardware_types [] = { + "unknown-0", + "ethernet", + "unknown-2", + "unknown-3", + "unknown-4", + "unknown-5", + "token-ring", + "unknown-7", + "unknown-8", + "unknown-9", + "unknown-10", + "unknown-11", + "unknown-12", + "unknown-13", + "unknown-14", + "unknown-15", + "unknown-16", + "unknown-17", + "unknown-18", + "unknown-19", + "unknown-20", + "unknown-21", + "unknown-22", + "unknown-23", + "unknown-24", + "unknown-25", + "unknown-26", + "unknown-27", + "unknown-28", + "unknown-29", + "unknown-30", + "unknown-31", + "unknown-32", + "unknown-33", + "unknown-34", + "unknown-35", + "unknown-36", + "unknown-37", + "unknown-38", + "unknown-39", + "unknown-40", + "unknown-41", + "unknown-42", + "unknown-43", + "unknown-44", + "unknown-45", + "unknown-46", + "unknown-47", + "unknown-48", + "unknown-49", + "unknown-50", + "unknown-51", + "unknown-52", + "unknown-53", + "unknown-54", + "unknown-55", + "unknown-56", + "unknown-57", + "unknown-58", + "unknown-59", + "unknown-60", + "unknown-61", + "unknown-62", + "unknown-63", + "unknown-64", + "unknown-65", + "unknown-66", + "unknown-67", + "unknown-68", + "unknown-69", + "unknown-70", + "unknown-71", + "unknown-72", + "unknown-73", + "unknown-74", + "unknown-75", + "unknown-76", + "unknown-77", + "unknown-78", + "unknown-79", + "unknown-80", + "unknown-81", + "unknown-82", + "unknown-83", + "unknown-84", + "unknown-85", + "unknown-86", + "unknown-87", + "unknown-88", + "unknown-89", + "unknown-90", + "unknown-91", + "unknown-92", + "unknown-93", + "unknown-94", + "unknown-95", + "unknown-96", + "unknown-97", + "unknown-98", + "unknown-99", + "unknown-100", + "unknown-101", + "unknown-102", + "unknown-103", + "unknown-104", + "unknown-105", + "unknown-106", + "unknown-107", + "unknown-108", + "unknown-109", + "unknown-110", + "unknown-111", + "unknown-112", + "unknown-113", + "unknown-114", + "unknown-115", + "unknown-116", + "unknown-117", + "unknown-118", + "unknown-119", + "unknown-120", + "unknown-121", + "unknown-122", + "unknown-123", + "unknown-124", + "unknown-125", + "unknown-126", + "unknown-127", + "unknown-128", + "unknown-129", + "unknown-130", + "unknown-131", + "unknown-132", + "unknown-133", + "unknown-134", + "unknown-135", + "unknown-136", + "unknown-137", + "unknown-138", + "unknown-139", + "unknown-140", + "unknown-141", + "unknown-142", + "unknown-143", + "unknown-144", + "unknown-145", + "unknown-146", + "unknown-147", + "unknown-148", + "unknown-149", + "unknown-150", + "unknown-151", + "unknown-152", + "unknown-153", + "unknown-154", + "unknown-155", + "unknown-156", + "unknown-157", + "unknown-158", + "unknown-159", + "unknown-160", + "unknown-161", + "unknown-162", + "unknown-163", + "unknown-164", + "unknown-165", + "unknown-166", + "unknown-167", + "unknown-168", + "unknown-169", + "unknown-170", + "unknown-171", + "unknown-172", + "unknown-173", + "unknown-174", + "unknown-175", + "unknown-176", + "unknown-177", + "unknown-178", + "unknown-179", + "unknown-180", + "unknown-181", + "unknown-182", + "unknown-183", + "unknown-184", + "unknown-185", + "unknown-186", + "unknown-187", + "unknown-188", + "unknown-189", + "unknown-190", + "unknown-191", + "unknown-192", + "unknown-193", + "unknown-194", + "unknown-195", + "unknown-196", + "unknown-197", + "unknown-198", + "unknown-199", + "unknown-200", + "unknown-201", + "unknown-202", + "unknown-203", + "unknown-204", + "unknown-205", + "unknown-206", + "unknown-207", + "unknown-208", + "unknown-209", + "unknown-210", + "unknown-211", + "unknown-212", + "unknown-213", + "unknown-214", + "unknown-215", + "unknown-216", + "unknown-217", + "unknown-218", + "unknown-219", + "unknown-220", + "unknown-221", + "unknown-222", + "unknown-223", + "unknown-224", + "unknown-225", + "unknown-226", + "unknown-227", + "unknown-228", + "unknown-229", + "unknown-230", + "unknown-231", + "unknown-232", + "unknown-233", + "unknown-234", + "unknown-235", + "unknown-236", + "unknown-237", + "unknown-238", + "unknown-239", + "unknown-240", + "unknown-241", + "unknown-242", + "unknown-243", + "unknown-244", + "unknown-245", + "unknown-246", + "unknown-247", + "unknown-248", + "unknown-249", + "unknown-250", + "unknown-251", + "unknown-252", + "unknown-253", + "unknown-254", + "unknown-255" }; + + + +struct hash_table universe_hash; + +void initialize_universes() +{ + int i; + + dhcp_universe.name = "dhcp"; + dhcp_universe.hash = new_hash (); + if (!dhcp_universe.hash) + error ("Can't allocate dhcp option hash table."); + for (i = 0; i < 256; i++) { + dhcp_universe.options [i] = &dhcp_options [i]; + add_hash (dhcp_universe.hash, + (unsigned char *)dhcp_options [i].name, 0, + (unsigned char *)&dhcp_options [i]); + } + universe_hash.hash_count = DEFAULT_HASH_SIZE; + add_hash (&universe_hash, + (unsigned char *)dhcp_universe.name, 0, + (unsigned char *)&dhcp_universe); +} diff --git a/contrib/isc-dhcp/common/tree.c b/contrib/isc-dhcp/common/tree.c new file mode 100644 index 0000000..ac83d67 --- /dev/null +++ b/contrib/isc-dhcp/common/tree.c @@ -0,0 +1,412 @@ +/* tree.c + + Routines for manipulating parse trees... */ + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: tree.c,v 1.10 1997/05/09 08:14:57 mellon Exp $ Copyright (c) 1995, 1996, 1997 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" + +static TIME tree_evaluate_recurse PROTO ((int *, unsigned char **, int *, + struct tree *)); +static TIME do_host_lookup PROTO ((int *, unsigned char **, int *, + struct dns_host_entry *)); +static void do_data_copy PROTO ((int *, unsigned char **, int *, + unsigned char *, int)); + +pair cons (car, cdr) + caddr_t car; + pair cdr; +{ + pair foo = (pair)dmalloc (sizeof *foo, "cons"); + if (!foo) + error ("no memory for cons."); + foo -> car = car; + foo -> cdr = cdr; + return foo; +} + +struct tree_cache *tree_cache (tree) + struct tree *tree; +{ + struct tree_cache *tc; + + tc = new_tree_cache ("tree_cache"); + if (!tc) + return 0; + tc -> value = (unsigned char *)0; + tc -> len = tc -> buf_size = 0; + tc -> timeout = 0; + tc -> tree = tree; + return tc; +} + +struct tree *tree_host_lookup (name) + char *name; +{ + struct tree *nt; + nt = new_tree ("tree_host_lookup"); + if (!nt) + error ("No memory for host lookup tree node."); + nt -> op = TREE_HOST_LOOKUP; + nt -> data.host_lookup.host = enter_dns_host (name); + return nt; +} + +struct dns_host_entry *enter_dns_host (name) + char *name; +{ + struct dns_host_entry *dh; + + if (!(dh = (struct dns_host_entry *)dmalloc + (sizeof (struct dns_host_entry), "enter_dns_host")) + || !(dh -> hostname = dmalloc (strlen (name) + 1, + "enter_dns_host"))) + error ("Can't allocate space for new host."); + strcpy (dh -> hostname, name); + dh -> data = (unsigned char *)0; + dh -> data_len = 0; + dh -> buf_len = 0; + dh -> timeout = 0; + return dh; +} + +struct tree *tree_const (data, len) + unsigned char *data; + int len; +{ + struct tree *nt; + if (!(nt = new_tree ("tree_const")) + || !(nt -> data.const_val.data = + (unsigned char *)dmalloc (len, "tree_const"))) + error ("No memory for constant data tree node."); + nt -> op = TREE_CONST; + memcpy (nt -> data.const_val.data, data, len); + nt -> data.const_val.len = len; + return nt; +} + +struct tree *tree_concat (left, right) + struct tree *left, *right; +{ + struct tree *nt; + + /* If we're concatenating a null tree to a non-null tree, just + return the non-null tree; if both trees are null, return + a null tree. */ + if (!left) + return right; + if (!right) + return left; + + /* If both trees are constant, combine them. */ + if (left -> op == TREE_CONST && right -> op == TREE_CONST) { + unsigned char *buf = dmalloc (left -> data.const_val.len + + right -> data.const_val.len, + "tree_concat"); + if (!buf) + error ("No memory to concatenate constants."); + memcpy (buf, left -> data.const_val.data, + left -> data.const_val.len); + memcpy (buf + left -> data.const_val.len, + right -> data.const_val.data, + right -> data.const_val.len); + dfree (left -> data.const_val.data, "tree_concat"); + dfree (right -> data.const_val.data, "tree_concat"); + left -> data.const_val.data = buf; + left -> data.const_val.len += right -> data.const_val.len; + free_tree (right, "tree_concat"); + return left; + } + + /* Otherwise, allocate a new node to concatenate the two. */ + if (!(nt = new_tree ("tree_concat"))) + error ("No memory for data tree concatenation node."); + nt -> op = TREE_CONCAT; + nt -> data.concat.left = left; + nt -> data.concat.right = right; + return nt; +} + +struct tree *tree_limit (tree, limit) + struct tree *tree; + int limit; +{ + struct tree *rv; + + /* If the tree we're limiting is constant, limit it now. */ + if (tree -> op == TREE_CONST) { + if (tree -> data.const_val.len > limit) + tree -> data.const_val.len = limit; + return tree; + } + + /* Otherwise, put in a node which enforces the limit on evaluation. */ + rv = new_tree ("tree_limit"); + if (!rv) + return (struct tree *)0; + rv -> op = TREE_LIMIT; + rv -> data.limit.tree = tree; + rv -> data.limit.limit = limit; + return rv; +} + +int tree_evaluate (tree_cache) + struct tree_cache *tree_cache; +{ + unsigned char *bp = tree_cache -> value; + int bc = tree_cache -> buf_size; + int bufix = 0; + + /* If there's no tree associated with this cache, it evaluates + to a constant and that was detected at startup. */ + if (!tree_cache -> tree) + return 1; + + /* Try to evaluate the tree without allocating more memory... */ + tree_cache -> timeout = tree_evaluate_recurse (&bufix, &bp, &bc, + tree_cache -> tree); + + /* No additional allocation needed? */ + if (bufix <= bc) { + tree_cache -> len = bufix; + return 1; + } + + /* If we can't allocate more memory, return with what we + have (maybe nothing). */ + if (!(bp = (unsigned char *)dmalloc (bufix, "tree_evaluate"))) + return 0; + + /* Record the change in conditions... */ + bc = bufix; + bufix = 0; + + /* Note that the size of the result shouldn't change on the + second call to tree_evaluate_recurse, since we haven't + changed the ``current'' time. */ + tree_evaluate_recurse (&bufix, &bp, &bc, tree_cache -> tree); + + /* Free the old buffer if needed, then store the new buffer + location and size and return. */ + if (tree_cache -> value) + dfree (tree_cache -> value, "tree_evaluate"); + tree_cache -> value = bp; + tree_cache -> len = bufix; + tree_cache -> buf_size = bc; + return 1; +} + +static TIME tree_evaluate_recurse (bufix, bufp, bufcount, tree) + int *bufix; + unsigned char **bufp; + int *bufcount; + struct tree *tree; +{ + int limit; + TIME t1, t2; + + switch (tree -> op) { + case TREE_CONCAT: + t1 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.concat.left); + t2 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.concat.right); + if (t1 > t2) + return t2; + return t1; + + case TREE_HOST_LOOKUP: + return do_host_lookup (bufix, bufp, bufcount, + tree -> data.host_lookup.host); + + case TREE_CONST: + do_data_copy (bufix, bufp, bufcount, + tree -> data.const_val.data, + tree -> data.const_val.len); + t1 = MAX_TIME; + return t1; + + case TREE_LIMIT: + limit = *bufix + tree -> data.limit.limit; + t1 = tree_evaluate_recurse (bufix, bufp, bufcount, + tree -> data.limit.tree); + *bufix = limit; + return t1; + + default: + warn ("Bad node id in tree: %d."); + t1 = MAX_TIME; + return t1; + } +} + +static TIME do_host_lookup (bufix, bufp, bufcount, dns) + int *bufix; + unsigned char **bufp; + int *bufcount; + struct dns_host_entry *dns; +{ + struct hostent *h; + int i; + int new_len; + +#ifdef DEBUG_EVAL + debug ("time: now = %d dns = %d %d diff = %d", + cur_time, dns -> timeout, cur_time - dns -> timeout); +#endif + + /* If the record hasn't timed out, just copy the data and return. */ + if (cur_time <= dns -> timeout) { +#ifdef DEBUG_EVAL + debug ("easy copy: %x %d %x", + dns -> data, dns -> data_len, + dns -> data ? *(int *)(dns -> data) : 0); +#endif + do_data_copy (bufix, bufp, bufcount, + dns -> data, dns -> data_len); + return dns -> timeout; + } +#ifdef DEBUG_EVAL + debug ("Looking up %s", dns -> hostname); +#endif + + /* Otherwise, look it up... */ + h = gethostbyname (dns -> hostname); + if (!h) { +#ifndef NO_H_ERRNO + switch (h_errno) { + case HOST_NOT_FOUND: +#endif + warn ("%s: host unknown.", dns -> hostname); +#ifndef NO_H_ERRNO + break; + case TRY_AGAIN: + warn ("%s: temporary name server failure", + dns -> hostname); + break; + case NO_RECOVERY: + warn ("%s: name server failed", dns -> hostname); + break; + case NO_DATA: + warn ("%s: no A record associated with address", + dns -> hostname); + } +#endif /* !NO_H_ERRNO */ + + /* Okay to try again after a minute. */ + return cur_time + 60; + } + +#ifdef DEBUG_EVAL + debug ("Lookup succeeded; first address is %x", + h -> h_addr_list [0]); +#endif + + /* Count the number of addresses we got... */ + for (i = 0; h -> h_addr_list [i]; i++) + ; + + /* Do we need to allocate more memory? */ + new_len = i * h -> h_length; + if (dns -> buf_len < i) { + unsigned char *buf = + (unsigned char *)dmalloc (new_len, "do_host_lookup"); + /* If we didn't get more memory, use what we have. */ + if (!buf) { + new_len = dns -> buf_len; + if (!dns -> buf_len) { + dns -> timeout = cur_time + 60; + return dns -> timeout; + } + } else { + if (dns -> data) + dfree (dns -> data, "do_host_lookup"); + dns -> data = buf; + dns -> buf_len = new_len; + } + } + + /* Addresses are conveniently stored one to the buffer, so we + have to copy them out one at a time... :'( */ + for (i = 0; i < new_len / h -> h_length; i++) { + memcpy (dns -> data + h -> h_length * i, + h -> h_addr_list [i], h -> h_length); + } +#ifdef DEBUG_EVAL + debug ("dns -> data: %x h -> h_addr_list [0]: %x", + *(int *)(dns -> data), h -> h_addr_list [0]); +#endif + dns -> data_len = new_len; + + /* Set the timeout for an hour from now. + XXX This should really use the time on the DNS reply. */ + dns -> timeout = cur_time + 3600; + +#ifdef DEBUG_EVAL + debug ("hard copy: %x %d %x", + dns -> data, dns -> data_len, *(int *)(dns -> data)); +#endif + do_data_copy (bufix, bufp, bufcount, dns -> data, dns -> data_len); + return dns -> timeout; +} + +static void do_data_copy (bufix, bufp, bufcount, data, len) + int *bufix; + unsigned char **bufp; + int *bufcount; + unsigned char *data; + int len; +{ + int space = *bufcount - *bufix; + + /* If there's more space than we need, use only what we need. */ + if (space > len) + space = len; + + /* Copy as much data as will fit, then increment the buffer index + by the amount we actually had to copy, which could be more. */ + if (space > 0) + memcpy (*bufp + *bufix, data, space); + *bufix += len; +} diff --git a/contrib/isc-dhcp/common/upf.c b/contrib/isc-dhcp/common/upf.c new file mode 100644 index 0000000..498b6e6 --- /dev/null +++ b/contrib/isc-dhcp/common/upf.c @@ -0,0 +1,298 @@ +/* upf.c + + Ultrix PacketFilter interface code. + +/* + * 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''. + */ + +#ifndef lint +static char copyright[] = +"$Id: upf.c,v 1.3 1997/10/20 21:47:15 mellon Exp $ Copyright (c) 1995, 1996 The Internet Software Consortium. All rights reserved.\n"; +#endif /* not lint */ + +#include "dhcpd.h" +#if defined (USE_UPF_SEND) || defined (USE_UPF_RECEIVE) +#include <sys/ioctl.h> +#include <sys/uio.h> + +#include <net/pfilt.h> +#include <netinet/in_systm.h> +#include "includes/netinet/ip.h" +#include "includes/netinet/udp.h" +#include "includes/netinet/if_ether.h" + +/* Reinitializes the specified interface after an address change. This + is not required for packet-filter APIs. */ + +#ifdef USE_UPF_SEND +void if_reinitialize_send (info) + struct interface_info *info; +{ +} +#endif + +#ifdef USE_UPF_RECEIVE +void if_reinitialize_receive (info) + struct interface_info *info; +{ +} +#endif + +/* 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_upf (info) + struct interface_info *info; +{ + int sock; + char filename[50]; + int b; + struct endevp param; + + /* Open a UPF device */ + for (b = 0; 1; b++) { +#ifndef NO_SNPRINTF + snprintf(filename, sizeof(filename), "/dev/pf/pfilt%d", b); +#else + sprintf(filename, "/dev/pf/pfilt%d", b); +#endif + sock = open (filename, O_RDWR, 0); + if (sock < 0) { + if (errno == EBUSY) { + continue; + } else { + error ("Can't find free upf: %m"); + } + } else { + break; + } + } + + /* Set the UPF device to point at this interface. */ + if (ioctl (sock, EIOCSETIF, info -> ifp) < 0) + error ("Can't attach interface %s to upf device %s: %m", + info -> name, filename); + + /* Get the hardware address. */ + if (ioctl (sock, EIOCDEVP, ¶m) < 0) + error ("Can't get interface %s hardware address: %m", + info -> name); + + /* We only know how to do ethernet. */ + if (param.end_dev_type != ENDT_10MB) + error ("Invalid device type on network interface %s: %d", + info -> name, param.end_dev_type); + + if (param.end_addr_len != 6) + error ("Invalid hardware address length on %s: %d", + info -> name, param.end_addr_len); + + info -> hw_address.hlen = 6; + info -> hw_address.htype = ARPHRD_ETHER; + memcpy (&info -> hw_address.haddr [0], param.end_addr, 6); + + return sock; +} +#endif /* USE_UPF_SEND || USE_UPF_RECEIVE */ + +#ifdef USE_UPF_SEND +void if_register_send (info) + struct interface_info *info; +{ + /* If we're using the upf API for sending and receiving, + we don't need to register this interface twice. */ +#ifndef USE_UPF_RECEIVE + info -> wfdesc = if_register_upf (info, interface); +#else + info -> wfdesc = info -> rfdesc; +#endif + if (!quiet_interface_discovery) + note ("Sending on UPF/%s/%s/%s", + info -> name, + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_UPF_SEND */ + +#ifdef USE_UPF_RECEIVE +/* Packet filter program... + XXX Changes to the filter program may require changes to the constant + offsets used in if_register_send to patch the UPF program! XXX */ + + +void if_register_receive (info) + struct interface_info *info; +{ + int flag = 1; + u_int32_t addr; + struct enfilter pf; + u_int32_t bits; + + /* Open a UPF device and hang it on this interface... */ + info -> rfdesc = if_register_upf (info); + + /* Allow the copyall flag to be set... */ + if (ioctl(info -> rfdesc, EIOCALLOWCOPYALL, &flag) < 0) + error ("Can't set ALLOWCOPYALL: %m"); + + /* Clear all the packet filter mode bits first... */ + flag = (ENHOLDSIG | ENBATCH | ENTSTAMP | ENPROMISC | + ENNONEXCL | ENCOPYALL); + if (ioctl (info -> rfdesc, EIOCMBIC, &flag) < 0) + error ("Can't clear pfilt bits: %m"); + + /* Set the ENBATCH and ENCOPYALL bits... */ + bits = ENBATCH | ENCOPYALL; + if (ioctl (info -> rfdesc, EIOCMBIS, &bits) < 0) + error ("Can't set ENBATCH|ENCOPYALL: %m"); + + /* Set up the UPF filter program. */ + /* XXX Unlike the BPF filter program, this one won't work if the + XXX IP packet is fragmented or if there are options on the IP + XXX header. */ + pf.enf_Priority = 0; + pf.enf_FilterLen = 0; + + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 6; + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; + pf.enf_Filter [pf.enf_FilterLen++] = htons (ETHERTYPE_IP); + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT; + pf.enf_Filter [pf.enf_FilterLen++] = htons (IPPROTO_UDP); + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 11; + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_AND; + pf.enf_Filter [pf.enf_FilterLen++] = htons (0xFF); + pf.enf_Filter [pf.enf_FilterLen++] = ENF_CAND; + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHWORD + 18; + pf.enf_Filter [pf.enf_FilterLen++] = ENF_PUSHLIT + ENF_CAND; + pf.enf_Filter [pf.enf_FilterLen++] = local_port; + + if (ioctl (info -> rfdesc, EIOCSETF, &pf) < 0) + error ("Can't install packet filter program: %m"); + if (!quiet_interface_discovery) + note ("Listening on UPF/%s/%s/%s", + info -> name, + print_hw_addr (info -> hw_address.htype, + info -> hw_address.hlen, + info -> hw_address.haddr), + (info -> shared_network ? + info -> shared_network -> name : "unattached")); +} +#endif /* USE_UPF_RECEIVE */ + +#ifdef USE_UPF_SEND +ssize_t send_packet (interface, packet, raw, len, from, to, hto) + struct interface_info *interface; + struct packet *packet; + struct dhcp_packet *raw; + size_t len; + struct in_addr from; + struct sockaddr_in *to; + struct hardware *hto; +{ + int bufp = 0; + unsigned char buf [256]; + struct iovec iov [2]; + + /* Assemble the headers... */ + assemble_hw_header (interface, buf, &bufp, hto); + assemble_udp_ip_header (interface, buf, &bufp, from.s_addr, + to -> sin_addr.s_addr, to -> sin_port, + (unsigned char *)raw, len); + + /* Fire it off */ + iov [0].iov_base = (char *)buf; + iov [0].iov_len = bufp; + iov [1].iov_base = (char *)raw; + iov [1].iov_len = len; + + return writev(interface -> wfdesc, iov, 2); +} +#endif /* USE_UPF_SEND */ + +#ifdef USE_UPF_RECEIVE +ssize_t receive_packet (interface, buf, len, from, hfrom) + struct interface_info *interface; + unsigned char *buf; + size_t len; + struct sockaddr_in *from; + struct hardware *hfrom; +{ + int nread; + int length = 0; + int offset = 0; + unsigned char ibuf [1500 + sizeof (struct enstamp)]; + int bufix = 0; + + length = read (interface -> rfdesc, ibuf, sizeof ibuf); + if (length <= 0) + return length; + + bufix = sizeof (struct enstamp); + /* Decode the physical header... */ + offset = decode_hw_header (interface, ibuf, bufix, hfrom); + + /* If a physical layer checksum failed (dunno of any + physical layer that supports this, but WTH), skip this + packet. */ + if (offset < 0) { + return 0; + } + + bufix += offset; + length -= offset; + + /* Decode the IP and UDP headers... */ + offset = decode_udp_ip_header (interface, ibuf, bufix, + from, (unsigned char *)0, length); + + /* If the IP or UDP checksum was bad, skip the packet... */ + if (offset < 0) + return 0; + + bufix += offset; + length -= offset; + + /* Copy out the data in the packet... */ + memcpy (buf, &ibuf [bufix], length); + return length; +} +#endif |