2007-05-08 23:05:22 +00:00
|
|
|
/* discover.c
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
Find and identify the network interfaces. */
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/*
|
2017-06-20 06:56:52 -04:00
|
|
|
* Copyright (c) 2004-2017 by Internet Systems Consortium, Inc. ("ISC")
|
2005-03-17 20:15:29 +00:00
|
|
|
* Copyright (c) 1995-2003 by Internet Software Consortium
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2017-07-12 09:23:23 -04:00
|
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
|
|
|
|
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
|
|
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
|
|
|
|
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
|
|
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
|
|
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
|
|
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
1998-11-06 00:19:56 +00:00
|
|
|
*
|
2005-03-17 20:15:29 +00:00
|
|
|
* Internet Systems Consortium, Inc.
|
|
|
|
* 950 Charter Street
|
|
|
|
* Redwood City, CA 94063
|
|
|
|
* <info@isc.org>
|
2009-07-23 18:52:21 +00:00
|
|
|
* https://www.isc.org/
|
2000-03-17 04:00:32 +00:00
|
|
|
*
|
1998-11-06 00:19:56 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dhcpd.h"
|
2007-05-19 18:47:15 +00:00
|
|
|
|
2014-04-25 10:50:24 -07:00
|
|
|
/* length of line we can read from the IF file, 256 is too small in some cases */
|
|
|
|
#define IF_LINE_LENGTH 1024
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#define BSD_COMP /* needed on Solaris for SIOCGLIFNUM */
|
1998-11-06 00:19:56 +00:00
|
|
|
#include <sys/ioctl.h>
|
2007-05-19 18:47:15 +00:00
|
|
|
#include <errno.h>
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-06-08 14:58:20 +00:00
|
|
|
#ifdef HAVE_NET_IF6_H
|
|
|
|
# include <net/if6.h>
|
|
|
|
#endif
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
struct interface_info *interfaces, *dummy_interfaces, *fallback_interface;
|
2001-06-27 00:31:20 +00:00
|
|
|
int interfaces_invalidated;
|
1998-11-06 00:19:56 +00:00
|
|
|
int quiet_interface_discovery;
|
2000-05-01 17:31:19 +00:00
|
|
|
u_int16_t local_port;
|
|
|
|
u_int16_t remote_port;
|
2016-02-23 10:40:10 +01:00
|
|
|
int dhcpv4_over_dhcpv6 = 0;
|
2000-05-16 23:03:49 +00:00
|
|
|
int (*dhcp_interface_setup_hook) (struct interface_info *, struct iaddr *);
|
|
|
|
int (*dhcp_interface_discovery_hook) (struct interface_info *);
|
2001-04-05 20:50:19 +00:00
|
|
|
isc_result_t (*dhcp_interface_startup_hook) (struct interface_info *);
|
2000-12-28 23:14:46 +00:00
|
|
|
int (*dhcp_interface_shutdown_hook) (struct interface_info *);
|
2000-05-01 17:31:19 +00:00
|
|
|
|
|
|
|
struct in_addr limited_broadcast;
|
2007-05-08 23:05:22 +00:00
|
|
|
|
2007-05-18 17:21:46 +00:00
|
|
|
int local_family = AF_INET;
|
2000-05-01 17:31:19 +00:00
|
|
|
struct in_addr local_address;
|
2007-05-19 18:47:15 +00:00
|
|
|
|
2011-05-11 14:01:25 +00:00
|
|
|
void (*bootp_packet_handler) (struct interface_info *,
|
|
|
|
struct dhcp_packet *, unsigned,
|
|
|
|
unsigned int,
|
|
|
|
struct iaddr, struct hardware *);
|
2007-05-19 18:47:15 +00:00
|
|
|
|
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
void (*dhcpv6_packet_handler)(struct interface_info *,
|
|
|
|
const char *, int,
|
|
|
|
int, const struct iaddr *,
|
|
|
|
isc_boolean_t);
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2007-05-08 23:05:22 +00:00
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
omapi_object_type_t *dhcp_type_interface;
|
2001-02-12 19:40:05 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
trace_type_t *interface_trace;
|
|
|
|
trace_type_t *inpacket_trace;
|
|
|
|
trace_type_t *outpacket_trace;
|
|
|
|
#endif
|
|
|
|
struct interface_info **interface_vector;
|
|
|
|
int interface_count;
|
|
|
|
int interface_max;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
OMAPI_OBJECT_ALLOC (interface, struct interface_info, dhcp_type_interface)
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t interface_setup ()
|
|
|
|
{
|
|
|
|
isc_result_t status;
|
|
|
|
status = omapi_object_type_register (&dhcp_type_interface,
|
|
|
|
"interface",
|
|
|
|
dhcp_interface_set_value,
|
|
|
|
dhcp_interface_get_value,
|
|
|
|
dhcp_interface_destroy,
|
|
|
|
dhcp_interface_signal_handler,
|
|
|
|
dhcp_interface_stuff_values,
|
|
|
|
dhcp_interface_lookup,
|
|
|
|
dhcp_interface_create,
|
|
|
|
dhcp_interface_remove,
|
|
|
|
0, 0, 0,
|
|
|
|
sizeof (struct interface_info),
|
2005-03-17 20:15:29 +00:00
|
|
|
interface_initialize, RC_MISC);
|
2000-12-28 23:14:46 +00:00
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Can't register interface object type: %s",
|
|
|
|
isc_result_totext (status));
|
2001-02-12 19:40:05 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
#if defined (TRACING)
|
|
|
|
void interface_trace_setup ()
|
|
|
|
{
|
|
|
|
interface_trace = trace_type_register ("interface", (void *)0,
|
|
|
|
trace_interface_input,
|
|
|
|
trace_interface_stop, MDL);
|
|
|
|
inpacket_trace = trace_type_register ("inpacket", (void *)0,
|
|
|
|
trace_inpacket_input,
|
|
|
|
trace_inpacket_stop, MDL);
|
|
|
|
outpacket_trace = trace_type_register ("outpacket", (void *)0,
|
|
|
|
trace_outpacket_input,
|
|
|
|
trace_outpacket_stop, MDL);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2000-10-10 22:31:41 +00:00
|
|
|
isc_result_t interface_initialize (omapi_object_t *ipo,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
struct interface_info *ip = (struct interface_info *)ipo;
|
|
|
|
ip -> rfdesc = ip -> wfdesc = -1;
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* Scanning for Interfaces
|
|
|
|
* -----------------------
|
|
|
|
*
|
|
|
|
* To find interfaces, we create an iterator that abstracts out most
|
|
|
|
* of the platform specifics. Use is fairly straightforward:
|
|
|
|
*
|
|
|
|
* - begin_iface_scan() starts the process.
|
|
|
|
* - Use next_iface() until it returns 0.
|
|
|
|
* - end_iface_scan() performs any necessary cleanup.
|
|
|
|
*
|
|
|
|
* We check for errors on each call to next_iface(), which returns a
|
|
|
|
* description of the error as a string if any occurs.
|
|
|
|
*
|
|
|
|
* We currently have code for Solaris and Linux. Other systems need
|
|
|
|
* to have code written.
|
|
|
|
*
|
|
|
|
* NOTE: the long-term goal is to use the interface code from BIND 9.
|
|
|
|
*/
|
|
|
|
|
2007-06-08 14:58:20 +00:00
|
|
|
#if defined(SIOCGLIFCONF) && defined(SIOCGLIFNUM) && defined(SIOCGLIFFLAGS)
|
|
|
|
|
|
|
|
/* HP/UX doesn't define struct lifconf, instead they define struct
|
|
|
|
* if_laddrconf. Similarly, 'struct lifreq' and 'struct lifaddrreq'.
|
|
|
|
*/
|
|
|
|
#ifdef ISC_PLATFORM_HAVEIF_LADDRCONF
|
|
|
|
# define lifc_len iflc_len
|
|
|
|
# define lifc_buf iflc_buf
|
|
|
|
# define lifc_req iflc_req
|
|
|
|
# define LIFCONF if_laddrconf
|
|
|
|
#else
|
|
|
|
# define ISC_HAVE_LIFC_FAMILY 1
|
|
|
|
# define ISC_HAVE_LIFC_FLAGS 1
|
|
|
|
# define LIFCONF lifconf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef ISC_PLATFORM_HAVEIF_LADDRREQ
|
|
|
|
# define lifr_addr iflr_addr
|
|
|
|
# define lifr_name iflr_name
|
|
|
|
# define lifr_dstaddr iflr_dstaddr
|
|
|
|
# define lifr_flags iflr_flags
|
|
|
|
# define sockaddr_storage sockaddr_ext
|
|
|
|
# define ss_family sa_family
|
|
|
|
# define LIFREQ if_laddrreq
|
|
|
|
#else
|
|
|
|
# define LIFREQ lifreq
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef IF_NAMESIZE
|
|
|
|
# if defined(LIFNAMSIZ)
|
|
|
|
# define IF_NAMESIZE LIFNAMSIZ
|
2009-04-30 18:42:52 +00:00
|
|
|
# elif defined(IFNAMSIZ)
|
2007-06-08 14:58:20 +00:00
|
|
|
# define IF_NAMESIZE IFNAMSIZ
|
|
|
|
# else
|
|
|
|
# define IF_NAMESIZE 16
|
|
|
|
# endif
|
|
|
|
#endif
|
2008-01-23 22:49:54 +00:00
|
|
|
#elif !defined(__linux) && !defined(HAVE_IFADDRS_H)
|
|
|
|
# define SIOCGLIFCONF SIOCGIFCONF
|
|
|
|
# define SIOCGLIFFLAGS SIOCGIFFLAGS
|
|
|
|
# define LIFREQ ifreq
|
|
|
|
# define LIFCONF ifconf
|
|
|
|
# define lifr_name ifr_name
|
|
|
|
# define lifr_addr ifr_addr
|
|
|
|
# define lifr_flags ifr_flags
|
|
|
|
# define lifc_len ifc_len
|
|
|
|
# define lifc_buf ifc_buf
|
|
|
|
# define lifc_req ifc_req
|
|
|
|
#ifdef _AIX
|
|
|
|
# define ss_family __ss_family
|
|
|
|
#endif
|
|
|
|
#endif
|
2007-06-08 14:58:20 +00:00
|
|
|
|
2008-01-23 22:49:54 +00:00
|
|
|
#if defined(SIOCGLIFCONF) && defined(SIOCGLIFFLAGS)
|
2007-05-08 23:05:22 +00:00
|
|
|
/*
|
|
|
|
* Solaris support
|
|
|
|
* ---------------
|
|
|
|
*
|
|
|
|
* The SIOCGLIFCONF ioctl() are the extension that you need to use
|
|
|
|
* on Solaris to get information about IPv6 addresses.
|
|
|
|
*
|
|
|
|
* Solaris' extended interface is documented in the if_tcp man page.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure holding state about the scan.
|
|
|
|
*/
|
|
|
|
struct iface_conf_list {
|
|
|
|
int sock; /* file descriptor used to get information */
|
|
|
|
int num; /* total number of interfaces */
|
2007-06-08 14:58:20 +00:00
|
|
|
struct LIFCONF conf; /* structure used to get information */
|
2007-05-08 23:05:22 +00:00
|
|
|
int next; /* next interface to retrieve when iterating */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure used to return information about a specific interface.
|
|
|
|
*/
|
|
|
|
struct iface_info {
|
2007-06-08 14:58:20 +00:00
|
|
|
char name[IF_NAMESIZE+1]; /* name of the interface, e.g. "bge0" */
|
2007-05-08 23:05:22 +00:00
|
|
|
struct sockaddr_storage addr; /* address information */
|
|
|
|
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a scan of interfaces.
|
|
|
|
*
|
|
|
|
* The iface_conf_list structure maintains state for this process.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
begin_iface_scan(struct iface_conf_list *ifaces) {
|
2007-06-08 14:58:20 +00:00
|
|
|
#ifdef ISC_PLATFORM_HAVELIFNUM
|
2007-05-08 23:05:22 +00:00
|
|
|
struct lifnum lifnum;
|
2007-06-08 14:58:20 +00:00
|
|
|
#else
|
|
|
|
int lifnum;
|
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
|
2007-08-14 14:08:16 +00:00
|
|
|
ifaces->sock = socket(local_family, SOCK_DGRAM, IPPROTO_UDP);
|
2007-05-08 23:05:22 +00:00
|
|
|
if (ifaces->sock < 0) {
|
|
|
|
log_error("Error creating socket to list interfaces; %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(&lifnum, 0, sizeof(lifnum));
|
2007-06-08 14:58:20 +00:00
|
|
|
#ifdef ISC_PLATFORM_HAVELIFNUM
|
2007-05-08 23:05:22 +00:00
|
|
|
lifnum.lifn_family = AF_UNSPEC;
|
2007-06-08 14:58:20 +00:00
|
|
|
#endif
|
2008-01-23 22:49:54 +00:00
|
|
|
#ifdef SIOCGLIFNUM
|
2007-05-08 23:05:22 +00:00
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFNUM, &lifnum) < 0) {
|
|
|
|
log_error("Error finding total number of interfaces; %m");
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-06-08 14:58:20 +00:00
|
|
|
#ifdef ISC_PLATFORM_HAVELIFNUM
|
2007-05-08 23:05:22 +00:00
|
|
|
ifaces->num = lifnum.lifn_count;
|
2007-06-08 14:58:20 +00:00
|
|
|
#else
|
|
|
|
ifaces->num = lifnum;
|
|
|
|
#endif
|
2008-01-23 22:49:54 +00:00
|
|
|
#else
|
|
|
|
ifaces->num = 64;
|
|
|
|
#endif /* SIOCGLIFNUM */
|
2007-06-08 14:58:20 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
memset(&ifaces->conf, 0, sizeof(ifaces->conf));
|
2007-06-08 14:58:20 +00:00
|
|
|
#ifdef ISC_HAVE_LIFC_FAMILY
|
2007-05-08 23:05:22 +00:00
|
|
|
ifaces->conf.lifc_family = AF_UNSPEC;
|
2007-06-08 14:58:20 +00:00
|
|
|
#endif
|
|
|
|
ifaces->conf.lifc_len = ifaces->num * sizeof(struct LIFREQ);
|
2007-05-08 23:05:22 +00:00
|
|
|
ifaces->conf.lifc_buf = dmalloc(ifaces->conf.lifc_len, MDL);
|
|
|
|
if (ifaces->conf.lifc_buf == NULL) {
|
|
|
|
log_fatal("Out of memory getting interface list.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFCONF, &ifaces->conf) < 0) {
|
|
|
|
log_error("Error getting interfaces configuration list; %m");
|
|
|
|
dfree(ifaces->conf.lifc_buf, MDL);
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifaces->next = 0;
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the next interface.
|
|
|
|
*
|
|
|
|
* Returns information in the info structure.
|
2007-05-16 22:27:35 +00:00
|
|
|
* Sets err to 1 if there is an error, otherwise 0.
|
2007-05-08 23:05:22 +00:00
|
|
|
*/
|
|
|
|
int
|
|
|
|
next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
2007-06-08 14:58:20 +00:00
|
|
|
struct LIFREQ *p;
|
|
|
|
struct LIFREQ tmp;
|
2011-06-27 16:00:32 +00:00
|
|
|
isc_boolean_t foundif;
|
2007-10-05 22:29:51 +00:00
|
|
|
#if defined(sun) || defined(__linux)
|
|
|
|
/* Pointer used to remove interface aliases. */
|
1998-11-06 00:19:56 +00:00
|
|
|
char *s;
|
2007-10-05 22:29:51 +00:00
|
|
|
#endif
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
do {
|
2011-06-27 16:00:32 +00:00
|
|
|
foundif = ISC_FALSE;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (ifaces->next >= ifaces->num) {
|
|
|
|
*err = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
p = ifaces->conf.lifc_req;
|
|
|
|
p += ifaces->next;
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (strlen(p->lifr_name) >= sizeof(info->name)) {
|
|
|
|
*err = 1;
|
|
|
|
log_error("Interface name '%s' too long", p->lifr_name);
|
|
|
|
return 0;
|
|
|
|
}
|
2011-06-27 16:00:32 +00:00
|
|
|
|
|
|
|
/* Reject if interface address family does not match */
|
|
|
|
if (p->lifr_addr.ss_family != local_family) {
|
|
|
|
ifaces->next++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2016-07-08 07:32:04 -04:00
|
|
|
memset(info, 0, sizeof(struct iface_info));
|
|
|
|
strncpy(info->name, p->lifr_name, sizeof(info->name) - 1);
|
2008-01-23 22:49:54 +00:00
|
|
|
memcpy(&info->addr, &p->lifr_addr, sizeof(p->lifr_addr));
|
2001-03-17 02:11:29 +00:00
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#if defined(sun) || defined(__linux)
|
2007-05-08 23:05:22 +00:00
|
|
|
/* interface aliases look like "eth0:1" or "wlan1:3" */
|
|
|
|
s = strchr(info->name, ':');
|
|
|
|
if (s != NULL) {
|
|
|
|
*s = '\0';
|
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* defined(sun) || defined(__linux) */
|
2007-05-08 23:05:22 +00:00
|
|
|
|
2011-06-27 16:00:32 +00:00
|
|
|
foundif = ISC_TRUE;
|
|
|
|
} while ((foundif == ISC_FALSE) ||
|
|
|
|
(strncmp(info->name, "dummy", 5) == 0));
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
memset(&tmp, 0, sizeof(tmp));
|
2016-07-08 07:32:04 -04:00
|
|
|
strncpy(tmp.lifr_name, info->name, sizeof(tmp.lifr_name) - 1);
|
2007-05-08 23:05:22 +00:00
|
|
|
if (ioctl(ifaces->sock, SIOCGLIFFLAGS, &tmp) < 0) {
|
|
|
|
log_error("Error getting interface flags for '%s'; %m",
|
|
|
|
p->lifr_name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
info->flags = tmp.lifr_flags;
|
|
|
|
|
|
|
|
ifaces->next++;
|
|
|
|
*err = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End scan of interfaces.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
end_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
dfree(ifaces->conf.lifc_buf, MDL);
|
|
|
|
close(ifaces->sock);
|
|
|
|
ifaces->sock = -1;
|
|
|
|
}
|
|
|
|
|
2008-01-23 22:49:54 +00:00
|
|
|
#else
|
2007-05-16 22:27:35 +00:00
|
|
|
|
|
|
|
/*
|
2017-03-08 16:01:38 +01:00
|
|
|
* BSD/Linux support
|
2007-05-16 22:27:35 +00:00
|
|
|
* -----------
|
|
|
|
*
|
2017-03-08 16:01:38 +01:00
|
|
|
* FreeBSD, NetBSD, OpenBSD, OS X/macOS and Linux all have the getifaddrs()
|
2007-05-16 22:27:35 +00:00
|
|
|
* function.
|
|
|
|
*
|
|
|
|
* The getifaddrs() man page describes the use.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ifaddrs.h>
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure holding state about the scan.
|
|
|
|
*/
|
|
|
|
struct iface_conf_list {
|
|
|
|
struct ifaddrs *head; /* beginning of the list */
|
|
|
|
struct ifaddrs *next; /* current position in the list */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Structure used to return information about a specific interface.
|
|
|
|
*/
|
|
|
|
struct iface_info {
|
|
|
|
char name[IFNAMSIZ]; /* name of the interface, e.g. "bge0" */
|
|
|
|
struct sockaddr_storage addr; /* address information */
|
|
|
|
isc_uint64_t flags; /* interface flags, e.g. IFF_LOOPBACK */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start a scan of interfaces.
|
|
|
|
*
|
|
|
|
* The iface_conf_list structure maintains state for this process.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
begin_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
if (getifaddrs(&ifaces->head) != 0) {
|
|
|
|
log_error("Error getting interfaces; %m");
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
ifaces->next = ifaces->head;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Retrieve the next interface.
|
|
|
|
*
|
|
|
|
* Returns information in the info structure.
|
|
|
|
* Sets err to 1 if there is an error, otherwise 0.
|
|
|
|
*/
|
|
|
|
int
|
|
|
|
next_iface(struct iface_info *info, int *err, struct iface_conf_list *ifaces) {
|
2017-03-08 16:01:38 +01:00
|
|
|
size_t sa_len = 0;
|
|
|
|
|
2007-05-16 22:27:35 +00:00
|
|
|
if (ifaces->next == NULL) {
|
|
|
|
*err = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (strlen(ifaces->next->ifa_name) >= sizeof(info->name)) {
|
|
|
|
log_error("Interface name '%s' too long",
|
|
|
|
ifaces->next->ifa_name);
|
|
|
|
*err = 1;
|
|
|
|
return 0;
|
|
|
|
}
|
2016-07-08 07:32:04 -04:00
|
|
|
memset(info, 0, sizeof(struct iface_info));
|
|
|
|
strncpy(info->name, ifaces->next->ifa_name, sizeof(info->name) - 1);
|
2017-03-08 16:01:38 +01:00
|
|
|
memset(&info->addr, 0 , sizeof(info->addr));
|
|
|
|
/*
|
|
|
|
* getifaddrs() can on Linux with some interfaces like PPP or TEQL
|
|
|
|
* result in a record with no address (ifa_addr).
|
|
|
|
*/
|
|
|
|
if (ifaces->next->ifa_addr != NULL) {
|
|
|
|
/* Linux lacks the sa_len member in struct sockaddr. */
|
|
|
|
#if defined(__linux)
|
|
|
|
if (ifaces->next->ifa_addr->sa_family == AF_INET)
|
|
|
|
sa_len = sizeof(struct sockaddr_in);
|
|
|
|
else if (ifaces->next->ifa_addr->sa_family == AF_INET6)
|
|
|
|
sa_len = sizeof(struct sockaddr_in6);
|
|
|
|
#else
|
|
|
|
sa_len = ifaces->next->ifa_addr->sa_len;
|
|
|
|
#endif
|
|
|
|
memcpy(&info->addr, ifaces->next->ifa_addr, sa_len);
|
|
|
|
}
|
2007-05-16 22:27:35 +00:00
|
|
|
info->flags = ifaces->next->ifa_flags;
|
|
|
|
ifaces->next = ifaces->next->ifa_next;
|
|
|
|
*err = 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* End scan of interfaces.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
end_iface_scan(struct iface_conf_list *ifaces) {
|
|
|
|
freeifaddrs(ifaces->head);
|
|
|
|
ifaces->head = NULL;
|
|
|
|
ifaces->next = NULL;
|
|
|
|
}
|
2007-05-08 23:05:22 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
/* XXX: perhaps create drealloc() rather than do it manually */
|
|
|
|
void
|
|
|
|
add_ipv4_addr_to_interface(struct interface_info *iface,
|
|
|
|
const struct in_addr *addr) {
|
|
|
|
/*
|
|
|
|
* We don't expect a lot of addresses per IPv4 interface, so
|
|
|
|
* we use 4, as our "chunk size" for collecting addresses.
|
|
|
|
*/
|
|
|
|
if (iface->addresses == NULL) {
|
|
|
|
iface->addresses = dmalloc(4 * sizeof(struct in_addr), MDL);
|
|
|
|
if (iface->addresses == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv4 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
iface->address_count = 0;
|
|
|
|
iface->address_max = 4;
|
|
|
|
} else if (iface->address_count >= iface->address_max) {
|
|
|
|
struct in_addr *tmp;
|
|
|
|
int new_max;
|
|
|
|
|
|
|
|
new_max = iface->address_max + 4;
|
|
|
|
tmp = dmalloc(new_max * sizeof(struct in_addr), MDL);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv4 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
memcpy(tmp,
|
|
|
|
iface->addresses,
|
|
|
|
iface->address_max * sizeof(struct in_addr));
|
|
|
|
dfree(iface->addresses, MDL);
|
|
|
|
iface->addresses = tmp;
|
|
|
|
iface->address_max = new_max;
|
|
|
|
}
|
|
|
|
iface->addresses[iface->address_count++] = *addr;
|
|
|
|
}
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
/* XXX: perhaps create drealloc() rather than do it manually */
|
|
|
|
void
|
|
|
|
add_ipv6_addr_to_interface(struct interface_info *iface,
|
|
|
|
const struct in6_addr *addr) {
|
|
|
|
/*
|
|
|
|
* Each IPv6 interface will have at least two IPv6 addresses,
|
|
|
|
* and likely quite a few more. So we use 8, as our "chunk size" for
|
|
|
|
* collecting addresses.
|
|
|
|
*/
|
|
|
|
if (iface->v6addresses == NULL) {
|
|
|
|
iface->v6addresses = dmalloc(8 * sizeof(struct in6_addr), MDL);
|
|
|
|
if (iface->v6addresses == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv6 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
iface->v6address_count = 0;
|
|
|
|
iface->v6address_max = 8;
|
|
|
|
} else if (iface->v6address_count >= iface->v6address_max) {
|
|
|
|
struct in6_addr *tmp;
|
|
|
|
int new_max;
|
|
|
|
|
|
|
|
new_max = iface->v6address_max + 8;
|
|
|
|
tmp = dmalloc(new_max * sizeof(struct in6_addr), MDL);
|
|
|
|
if (tmp == NULL) {
|
|
|
|
log_fatal("Out of memory saving IPv6 address "
|
|
|
|
"on interface.");
|
|
|
|
}
|
|
|
|
memcpy(tmp,
|
|
|
|
iface->v6addresses,
|
|
|
|
iface->v6address_max * sizeof(struct in6_addr));
|
|
|
|
dfree(iface->v6addresses, MDL);
|
|
|
|
iface->v6addresses = tmp;
|
|
|
|
iface->v6address_max = new_max;
|
|
|
|
}
|
|
|
|
iface->v6addresses[iface->v6address_count++] = *addr;
|
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
/* 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(int state) {
|
|
|
|
struct iface_conf_list ifaces;
|
|
|
|
struct iface_info info;
|
|
|
|
int err;
|
|
|
|
|
2007-07-13 06:43:43 +00:00
|
|
|
struct interface_info *tmp;
|
2007-05-08 23:05:22 +00:00
|
|
|
struct interface_info *last, *next;
|
|
|
|
|
2007-07-13 06:43:43 +00:00
|
|
|
#ifdef DHCPv6
|
|
|
|
char abuf[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
|
|
|
|
#endif /* DHCPv6 */
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
struct subnet *subnet;
|
|
|
|
int ir;
|
|
|
|
isc_result_t status;
|
|
|
|
int wifcount = 0;
|
|
|
|
|
|
|
|
static int setup_fallback = 0;
|
|
|
|
|
|
|
|
if (!begin_iface_scan(&ifaces)) {
|
|
|
|
log_fatal("Can't get list of interfaces.");
|
2000-09-04 22:27:41 +00:00
|
|
|
}
|
2001-05-02 06:36:54 +00:00
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* 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;
|
2016-08-10 14:31:26 -04:00
|
|
|
else {
|
1998-11-06 00:19:56 +00:00
|
|
|
ir = INTERFACE_REQUESTED;
|
2016-08-10 14:31:26 -04:00
|
|
|
if (state == DISCOVER_RELAY && local_family == AF_INET) {
|
|
|
|
/* We're a v4 relay without specifically requested
|
|
|
|
* interfaces, so mark them all as bidirectional. */
|
|
|
|
ir |= INTERFACE_STREAMS;
|
|
|
|
}
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
/* Cycle through the list of interfaces looking for IP addresses. */
|
2007-05-08 23:05:22 +00:00
|
|
|
while (next_iface(&info, &err, &ifaces)) {
|
1998-11-06 00:19:56 +00:00
|
|
|
|
1998-11-11 07:50:51 +00:00
|
|
|
/* See if we've seen an interface that matches this one. */
|
2007-05-08 23:05:22 +00:00
|
|
|
for (tmp = interfaces; tmp; tmp = tmp->next) {
|
|
|
|
if (!strcmp(tmp->name, info.name))
|
1998-11-11 07:50:51 +00:00
|
|
|
break;
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
1998-11-11 07:50:51 +00:00
|
|
|
|
2005-03-17 20:15:29 +00:00
|
|
|
/* Skip non broadcast interfaces (plus loopback and
|
|
|
|
point-to-point in case an OS incorrectly marks them
|
|
|
|
as broadcast). Also skip down interfaces unless we're
|
|
|
|
trying to get a list of configurable interfaces. */
|
2011-06-27 16:00:32 +00:00
|
|
|
if ((((local_family == AF_INET &&
|
|
|
|
!(info.flags & IFF_BROADCAST)) ||
|
|
|
|
#ifdef DHCPv6
|
|
|
|
(local_family == AF_INET6 &&
|
|
|
|
!(info.flags & IFF_MULTICAST)) ||
|
|
|
|
#endif
|
2007-05-08 23:05:22 +00:00
|
|
|
info.flags & IFF_LOOPBACK ||
|
|
|
|
info.flags & IFF_POINTOPOINT) && !tmp) ||
|
|
|
|
(!(info.flags & IFF_UP) &&
|
1998-11-06 00:19:56 +00:00
|
|
|
state != DISCOVER_UNCONFIGURED))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If there isn't already an interface by this name,
|
|
|
|
allocate one. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (tmp == NULL) {
|
|
|
|
status = interface_allocate(&tmp, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS) {
|
|
|
|
log_fatal("Error allocating interface %s: %s",
|
|
|
|
info.name, isc_result_totext(status));
|
|
|
|
}
|
2016-07-08 07:32:04 -04:00
|
|
|
strncpy(tmp->name, info.name, sizeof(tmp->name) - 1);
|
2007-05-08 23:05:22 +00:00
|
|
|
interface_snorf(tmp, ir);
|
|
|
|
interface_dereference(&tmp, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
tmp = interfaces; /* XXX */
|
2000-01-28 20:30:37 +00:00
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (dhcp_interface_discovery_hook) {
|
|
|
|
(*dhcp_interface_discovery_hook)(tmp);
|
|
|
|
}
|
2000-05-16 23:03:49 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if ((info.addr.ss_family == AF_INET) &&
|
|
|
|
(local_family == AF_INET)) {
|
|
|
|
struct sockaddr_in *a = (struct sockaddr_in*)&info.addr;
|
1998-11-06 00:19:56 +00:00
|
|
|
struct iaddr addr;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* We don't want the loopback interface. */
|
|
|
|
if (a->sin_addr.s_addr == htonl(INADDR_LOOPBACK) &&
|
|
|
|
((tmp->flags & INTERFACE_AUTOMATIC) &&
|
2016-02-23 10:40:10 +01:00
|
|
|
((state == DISCOVER_SERVER) ||
|
|
|
|
(state == DISCOVER_SERVER46))))
|
2007-05-08 23:05:22 +00:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* If the only address we have is 0.0.0.0, we
|
|
|
|
shouldn't consider the interface configured. */
|
|
|
|
if (a->sin_addr.s_addr != htonl(INADDR_ANY))
|
|
|
|
tmp->configured = 1;
|
|
|
|
|
|
|
|
add_ipv4_addr_to_interface(tmp, &a->sin_addr);
|
|
|
|
|
|
|
|
/* invoke the setup hook */
|
|
|
|
addr.len = 4;
|
|
|
|
memcpy(addr.iabuf, &a->sin_addr.s_addr, addr.len);
|
|
|
|
if (dhcp_interface_setup_hook) {
|
|
|
|
(*dhcp_interface_setup_hook)(tmp, &addr);
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
else if ((info.addr.ss_family == AF_INET6) &&
|
|
|
|
(local_family == AF_INET6)) {
|
|
|
|
struct sockaddr_in6 *a =
|
|
|
|
(struct sockaddr_in6*)&info.addr;
|
|
|
|
struct iaddr addr;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* We don't want the loopback interface. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (IN6_IS_ADDR_LOOPBACK(&a->sin6_addr) &&
|
|
|
|
((tmp->flags & INTERFACE_AUTOMATIC) &&
|
2016-02-23 10:40:10 +01:00
|
|
|
((state == DISCOVER_SERVER) ||
|
|
|
|
(state == DISCOVER_SERVER46))))
|
2006-08-09 14:57:48 +00:00
|
|
|
continue;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
/* If the only address we have is 0.0.0.0, we
|
|
|
|
shouldn't consider the interface configured. */
|
|
|
|
if (IN6_IS_ADDR_UNSPECIFIED(&a->sin6_addr))
|
|
|
|
tmp->configured = 1;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
add_ipv6_addr_to_interface(tmp, &a->sin6_addr);
|
|
|
|
|
|
|
|
/* invoke the setup hook */
|
|
|
|
addr.len = 16;
|
|
|
|
memcpy(addr.iabuf, &a->sin6_addr, addr.len);
|
|
|
|
if (dhcp_interface_setup_hook) {
|
|
|
|
(*dhcp_interface_setup_hook)(tmp, &addr);
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (err) {
|
|
|
|
log_fatal("Error getting interface information.");
|
|
|
|
}
|
|
|
|
|
|
|
|
end_iface_scan(&ifaces);
|
2000-09-04 22:27:41 +00:00
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
|
2007-05-18 17:21:46 +00:00
|
|
|
/* Mock-up an 'ifp' structure which is no longer used in the
|
|
|
|
* new interface-sensing code, but is used in higher layers
|
|
|
|
* (for example to sense fallback interfaces).
|
|
|
|
*/
|
|
|
|
for (tmp = interfaces ; tmp != NULL ; tmp = tmp->next) {
|
|
|
|
if (tmp->ifp == NULL) {
|
|
|
|
struct ifreq *tif;
|
|
|
|
|
|
|
|
tif = (struct ifreq *)dmalloc(sizeof(struct ifreq),
|
|
|
|
MDL);
|
|
|
|
if (tif == NULL)
|
|
|
|
log_fatal("no space for ifp mockup.");
|
|
|
|
strcpy(tif->ifr_name, tmp->name);
|
|
|
|
tmp->ifp = tif;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* If we're just trying to get a list of interfaces that we might
|
|
|
|
be able to configure, we can quit now. */
|
2000-02-15 20:40:36 +00:00
|
|
|
if (state == DISCOVER_UNCONFIGURED) {
|
1998-11-06 00:19:56 +00:00
|
|
|
return;
|
2000-02-15 20:40:36 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* Weed out the interfaces that did not have IP addresses. */
|
2007-05-08 23:05:22 +00:00
|
|
|
tmp = last = next = NULL;
|
2000-05-16 23:03:49 +00:00
|
|
|
if (interfaces)
|
|
|
|
interface_reference (&tmp, interfaces, MDL);
|
|
|
|
while (tmp) {
|
|
|
|
if (next)
|
|
|
|
interface_dereference (&next, MDL);
|
|
|
|
if (tmp -> next)
|
|
|
|
interface_reference (&next, tmp -> next, MDL);
|
2000-01-28 20:30:37 +00:00
|
|
|
/* skip interfaces that are running already */
|
2005-03-17 20:15:29 +00:00
|
|
|
if (tmp -> flags & INTERFACE_RUNNING) {
|
|
|
|
interface_dereference(&tmp, MDL);
|
|
|
|
if(next)
|
|
|
|
interface_reference(&tmp, next, MDL);
|
2000-01-28 20:30:37 +00:00
|
|
|
continue;
|
2005-03-17 20:15:29 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((tmp -> flags & INTERFACE_AUTOMATIC) &&
|
|
|
|
state == DISCOVER_REQUESTED)
|
|
|
|
tmp -> flags &= ~(INTERFACE_AUTOMATIC |
|
|
|
|
INTERFACE_REQUESTED);
|
2007-05-19 18:47:15 +00:00
|
|
|
|
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
if (!(tmp->flags & INTERFACE_REQUESTED)) {
|
2007-05-19 18:47:15 +00:00
|
|
|
#else
|
|
|
|
if (!tmp -> ifp || !(tmp -> flags & INTERFACE_REQUESTED)) {
|
|
|
|
#endif /* DHCPv6 */
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((tmp -> flags & INTERFACE_REQUESTED) != ir)
|
1999-02-24 17:56:53 +00:00
|
|
|
log_fatal ("%s: not found", tmp -> name);
|
2000-05-16 23:03:49 +00:00
|
|
|
if (!last) {
|
|
|
|
if (interfaces)
|
|
|
|
interface_dereference (&interfaces,
|
|
|
|
MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (next)
|
2000-05-16 23:03:49 +00:00
|
|
|
interface_reference (&interfaces, next, MDL);
|
|
|
|
} else {
|
|
|
|
interface_dereference (&last -> next, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (next)
|
|
|
|
interface_reference (&last -> next,
|
|
|
|
next, MDL);
|
2000-05-16 23:03:49 +00:00
|
|
|
}
|
|
|
|
if (tmp -> next)
|
|
|
|
interface_dereference (&tmp -> next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* Remember the interface in case we need to know
|
|
|
|
about it later. */
|
2000-05-16 23:03:49 +00:00
|
|
|
if (dummy_interfaces) {
|
|
|
|
interface_reference (&tmp -> next,
|
|
|
|
dummy_interfaces, MDL);
|
|
|
|
interface_dereference (&dummy_interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&dummy_interfaces, tmp, MDL);
|
|
|
|
interface_dereference (&tmp, MDL);
|
|
|
|
if (next)
|
|
|
|
interface_reference (&tmp, next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
last = tmp;
|
|
|
|
|
|
|
|
/* We must have a subnet declaration for each interface. */
|
2007-05-08 23:05:22 +00:00
|
|
|
if (!tmp->shared_network && (state == DISCOVER_SERVER)) {
|
|
|
|
log_error("%s", "");
|
|
|
|
if (local_family == AF_INET) {
|
|
|
|
log_error("No subnet declaration for %s (%s).",
|
|
|
|
tmp->name,
|
2007-06-01 22:11:49 +00:00
|
|
|
(tmp->addresses == NULL) ?
|
|
|
|
"no IPv4 addresses" :
|
|
|
|
inet_ntoa(tmp->addresses[0]));
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
} else {
|
|
|
|
if (tmp->v6addresses != NULL) {
|
|
|
|
inet_ntop(AF_INET6,
|
|
|
|
&tmp->v6addresses[0],
|
|
|
|
abuf,
|
|
|
|
sizeof(abuf));
|
|
|
|
} else {
|
2007-06-01 22:11:49 +00:00
|
|
|
strcpy(abuf, "no IPv6 addresses");
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
2008-02-13 06:41:05 +00:00
|
|
|
log_error("No subnet6 declaration for %s (%s).",
|
2007-05-08 23:05:22 +00:00
|
|
|
tmp->name,
|
|
|
|
abuf);
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
|
|
|
if (supports_multiple_interfaces(tmp)) {
|
2001-01-03 23:13:46 +00:00
|
|
|
log_error ("** Ignoring requests on %s. %s",
|
|
|
|
tmp -> name, "If this is not what");
|
|
|
|
log_error (" you want, please write %s",
|
2008-02-13 06:41:05 +00:00
|
|
|
#ifdef DHCPv6
|
|
|
|
(local_family != AF_INET) ?
|
|
|
|
"a subnet6 declaration" :
|
|
|
|
#endif
|
2001-01-03 23:13:46 +00:00
|
|
|
"a subnet declaration");
|
|
|
|
log_error (" in your dhcpd.conf file %s",
|
|
|
|
"for the network segment");
|
|
|
|
log_error (" to %s %s %s",
|
2000-09-01 23:03:39 +00:00
|
|
|
"which interface",
|
2001-01-03 23:13:46 +00:00
|
|
|
tmp -> name, "is attached. **");
|
|
|
|
log_error ("%s", "");
|
2000-09-01 23:03:39 +00:00
|
|
|
goto next;
|
|
|
|
} else {
|
2008-02-13 06:41:05 +00:00
|
|
|
log_error ("You must write a %s",
|
|
|
|
#ifdef DHCPv6
|
|
|
|
(local_family != AF_INET) ?
|
|
|
|
"subnet6 declaration for this" :
|
|
|
|
#endif
|
|
|
|
"subnet declaration for this");
|
2000-09-01 23:03:39 +00:00
|
|
|
log_error ("subnet. You cannot prevent %s",
|
|
|
|
"the DHCP server");
|
|
|
|
log_error ("from listening on this subnet %s",
|
|
|
|
"because your");
|
|
|
|
log_fatal ("operating system does not %s.",
|
|
|
|
"support this capability");
|
|
|
|
}
|
1999-02-25 23:30:43 +00:00
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
/* 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) {
|
2007-08-14 14:08:16 +00:00
|
|
|
/* Set the interface address for this subnet
|
|
|
|
to the first address we found. */
|
|
|
|
if (subnet->interface_address.len == 0) {
|
|
|
|
if (tmp->address_count > 0) {
|
|
|
|
subnet->interface_address.len = 4;
|
|
|
|
memcpy(subnet->interface_address.iabuf,
|
|
|
|
&tmp->addresses[0].s_addr, 4);
|
|
|
|
} else if (tmp->v6address_count > 0) {
|
|
|
|
subnet->interface_address.len = 16;
|
|
|
|
memcpy(subnet->interface_address.iabuf,
|
|
|
|
&tmp->v6addresses[0].s6_addr,
|
|
|
|
16);
|
|
|
|
} else {
|
|
|
|
/* XXX: should be one */
|
|
|
|
log_error("%s missing an interface "
|
|
|
|
"address", tmp->name);
|
|
|
|
continue;
|
|
|
|
}
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
/* Flag the index as not having been set, so that the
|
|
|
|
interface registerer can set it or not as it chooses. */
|
|
|
|
tmp -> index = -1;
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
/* Register the interface... */
|
2016-02-23 10:40:10 +01:00
|
|
|
switch (local_family) {
|
|
|
|
case AF_INET:
|
|
|
|
if (!dhcpv4_over_dhcpv6) {
|
|
|
|
if_register_receive(tmp);
|
|
|
|
if_register_send(tmp);
|
|
|
|
} else {
|
|
|
|
/* get_hw_addr() was called by register. */
|
|
|
|
get_hw_addr(tmp->name, &tmp->hw_address);
|
|
|
|
}
|
|
|
|
break;
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2016-02-23 10:40:10 +01:00
|
|
|
case AF_INET6:
|
2008-06-13 00:55:53 +00:00
|
|
|
if ((state == DISCOVER_SERVER) ||
|
|
|
|
(state == DISCOVER_RELAY)) {
|
2007-05-08 23:05:22 +00:00
|
|
|
if_register6(tmp, 1);
|
2016-02-23 10:40:10 +01:00
|
|
|
} else if (state == DISCOVER_SERVER46) {
|
|
|
|
/* get_hw_addr() was called by if_register*6
|
|
|
|
so now we have to call it explicitly
|
|
|
|
to not leave the hardware address unknown
|
|
|
|
(some code expects it cannot be. */
|
|
|
|
get_hw_addr(tmp->name, &tmp->hw_address);
|
2007-05-08 23:05:22 +00:00
|
|
|
} else {
|
2013-10-21 14:59:41 -07:00
|
|
|
if_register_linklocal6(tmp);
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
2016-02-23 10:40:10 +01:00
|
|
|
break;
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
2001-02-12 19:40:05 +00:00
|
|
|
|
|
|
|
interface_stash (tmp);
|
2000-09-04 22:27:41 +00:00
|
|
|
wifcount++;
|
2007-05-19 18:47:15 +00:00
|
|
|
#if defined (F_SETFD)
|
2016-02-23 10:40:10 +01:00
|
|
|
/* if_register*() are no longer always called so
|
|
|
|
descriptors must be checked. */
|
|
|
|
if ((tmp -> rfdesc >= 0) &&
|
|
|
|
(fcntl (tmp -> rfdesc, F_SETFD, 1) < 0))
|
|
|
|
log_error ("Can't set close-on-exec on %s: %m",
|
|
|
|
tmp -> name);
|
|
|
|
if ((tmp -> wfdesc != tmp -> rfdesc) &&
|
|
|
|
(tmp -> wfdesc >= 0) &&
|
|
|
|
(fcntl (tmp -> wfdesc, F_SETFD, 1) < 0))
|
2000-01-05 18:00:34 +00:00
|
|
|
log_error ("Can't set close-on-exec on %s: %m",
|
|
|
|
tmp -> name);
|
|
|
|
#endif
|
2000-09-01 23:03:39 +00:00
|
|
|
next:
|
2000-05-16 23:03:49 +00:00
|
|
|
interface_dereference (&tmp, MDL);
|
|
|
|
if (next)
|
|
|
|
interface_reference (&tmp, next, MDL);
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
/*
|
|
|
|
* Now register all the remaining interfaces as protocols.
|
|
|
|
* We register with omapi to allow for control of the interface,
|
|
|
|
* we've already registered the fd or socket with the socket
|
|
|
|
* manager as part of if_register_receive().
|
|
|
|
*/
|
1999-09-08 01:44:08 +00:00
|
|
|
for (tmp = interfaces; tmp; tmp = tmp -> next) {
|
2000-01-28 20:30:37 +00:00
|
|
|
/* not if it's been registered before */
|
|
|
|
if (tmp -> flags & INTERFACE_RUNNING)
|
|
|
|
continue;
|
2000-10-10 22:31:41 +00:00
|
|
|
if (tmp -> rfdesc == -1)
|
|
|
|
continue;
|
2009-10-28 04:12:30 +00:00
|
|
|
switch (local_family) {
|
2007-08-22 13:41:37 +00:00
|
|
|
#ifdef DHCPv6
|
2009-10-28 04:12:30 +00:00
|
|
|
case AF_INET6:
|
2007-05-08 23:05:22 +00:00
|
|
|
status = omapi_register_io_object((omapi_object_t *)tmp,
|
|
|
|
if_readsocket,
|
2007-08-22 13:41:37 +00:00
|
|
|
0, got_one_v6, 0, 0);
|
2009-10-28 04:12:30 +00:00
|
|
|
break;
|
2007-08-22 13:41:37 +00:00
|
|
|
#endif /* DHCPv6 */
|
2009-10-28 04:12:30 +00:00
|
|
|
case AF_INET:
|
|
|
|
default:
|
2007-05-08 23:05:22 +00:00
|
|
|
status = omapi_register_io_object((omapi_object_t *)tmp,
|
|
|
|
if_readsocket,
|
2007-08-22 13:41:37 +00:00
|
|
|
0, got_one, 0, 0);
|
2009-10-28 04:12:30 +00:00
|
|
|
break;
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
2009-10-28 04:12:30 +00:00
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Can't register I/O handle for %s: %s",
|
|
|
|
tmp -> name, isc_result_totext (status));
|
2008-08-29 17:48:57 +00:00
|
|
|
|
|
|
|
#if defined(DHCPv6)
|
2013-10-21 14:59:41 -07:00
|
|
|
/* Only register the first interface for V6, since
|
|
|
|
* servers and relays all use the same socket.
|
|
|
|
* XXX: This has some messy side effects if we start
|
|
|
|
* dynamically adding and removing interfaces, but
|
|
|
|
* we're well beyond that point in terms of mess.
|
2008-08-29 17:48:57 +00:00
|
|
|
*/
|
2013-10-21 14:59:41 -07:00
|
|
|
if (((state == DISCOVER_SERVER) || (state == DISCOVER_RELAY)) &&
|
|
|
|
(local_family == AF_INET6))
|
2008-08-29 17:48:57 +00:00
|
|
|
break;
|
|
|
|
#endif
|
2009-10-28 04:12:30 +00:00
|
|
|
} /* for (tmp = interfaces; ... */
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2000-09-04 22:27:41 +00:00
|
|
|
if (state == DISCOVER_SERVER && wifcount == 0) {
|
|
|
|
log_info ("%s", "");
|
|
|
|
log_fatal ("Not configured to listen on any interfaces!");
|
|
|
|
}
|
|
|
|
|
2016-02-23 10:40:10 +01:00
|
|
|
if ((local_family == AF_INET) &&
|
|
|
|
!setup_fallback && !dhcpv4_over_dhcpv6) {
|
2000-02-15 20:40:36 +00:00
|
|
|
setup_fallback = 1;
|
2007-05-08 23:05:22 +00:00
|
|
|
maybe_setup_fallback();
|
2000-02-15 20:40:36 +00:00
|
|
|
}
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#if defined (F_SETFD)
|
2000-01-05 18:00:34 +00:00
|
|
|
if (fallback_interface) {
|
|
|
|
if (fcntl (fallback_interface -> rfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on fallback: %m");
|
|
|
|
if (fallback_interface -> rfdesc != fallback_interface -> wfdesc) {
|
|
|
|
if (fcntl (fallback_interface -> wfdesc, F_SETFD, 1) < 0)
|
|
|
|
log_error ("Can't set close-on-exec on fallback: %m");
|
|
|
|
}
|
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* F_SETFD */
|
1999-02-14 19:04:05 +00:00
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
int if_readsocket (h)
|
|
|
|
omapi_object_t *h;
|
|
|
|
{
|
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
2000-03-06 22:52:16 +00:00
|
|
|
return -1;
|
1999-09-08 01:44:08 +00:00
|
|
|
ip = (struct interface_info *)h;
|
|
|
|
return ip -> rfdesc;
|
|
|
|
}
|
|
|
|
|
2000-05-16 23:03:49 +00:00
|
|
|
int setup_fallback (struct interface_info **fp, const char *file, int line)
|
1999-02-14 19:04:05 +00:00
|
|
|
{
|
2000-05-16 23:03:49 +00:00
|
|
|
isc_result_t status;
|
|
|
|
|
|
|
|
status = interface_allocate (&fallback_interface, file, line);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
log_fatal ("Error allocating fallback interface: %s",
|
|
|
|
isc_result_totext (status));
|
1999-02-14 19:04:05 +00:00
|
|
|
strcpy (fallback_interface -> name, "fallback");
|
2000-05-16 23:03:49 +00:00
|
|
|
if (dhcp_interface_setup_hook)
|
|
|
|
(*dhcp_interface_setup_hook) (fallback_interface,
|
|
|
|
(struct iaddr *)0);
|
|
|
|
status = interface_reference (fp, fallback_interface, file, line);
|
2001-02-12 19:40:05 +00:00
|
|
|
|
2001-02-17 21:16:44 +00:00
|
|
|
fallback_interface -> index = -1;
|
2001-02-12 19:40:05 +00:00
|
|
|
interface_stash (fallback_interface);
|
2000-05-16 23:03:49 +00:00
|
|
|
return status == ISC_R_SUCCESS;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reinitialize_interfaces ()
|
|
|
|
{
|
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
for (ip = interfaces; ip; ip = ip -> next) {
|
|
|
|
if_reinitialize_receive (ip);
|
|
|
|
if_reinitialize_send (ip);
|
|
|
|
}
|
|
|
|
|
1999-02-14 19:04:05 +00:00
|
|
|
if (fallback_interface)
|
|
|
|
if_reinitialize_send (fallback_interface);
|
1998-11-06 00:19:56 +00:00
|
|
|
|
|
|
|
interfaces_invalidated = 1;
|
|
|
|
}
|
1999-02-14 19:04:05 +00:00
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
isc_result_t got_one (h)
|
|
|
|
omapi_object_t *h;
|
1998-11-06 00:19:56 +00:00
|
|
|
{
|
|
|
|
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;
|
1999-09-08 01:44:08 +00:00
|
|
|
struct interface_info *ip;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
1999-09-08 01:44:08 +00:00
|
|
|
ip = (struct interface_info *)h;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
again:
|
1998-11-06 00:19:56 +00:00
|
|
|
if ((result =
|
|
|
|
receive_packet (ip, u.packbuf, sizeof u, &from, &hfrom)) < 0) {
|
1999-02-24 17:56:53 +00:00
|
|
|
log_error ("receive_packet failed on %s: %m", ip -> name);
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_UNEXPECTED;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
if (result == 0)
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_UNEXPECTED;
|
1998-11-06 00:19:56 +00:00
|
|
|
|
2011-07-19 22:13:26 +00:00
|
|
|
/*
|
|
|
|
* If we didn't at least get the fixed portion of the BOOTP
|
|
|
|
* packet, drop the packet.
|
|
|
|
* Previously we allowed packets with no sname or filename
|
|
|
|
* as we were aware of at least one client that did. But
|
|
|
|
* a bug caused short packets to not work and nobody has
|
|
|
|
* complained, it seems rational to tighten up that
|
|
|
|
* restriction.
|
|
|
|
*/
|
|
|
|
if (result < DHCP_FIXED_NON_UDP)
|
1999-10-08 17:08:34 +00:00
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
|
2011-06-27 16:00:32 +00:00
|
|
|
#if defined(IP_PKTINFO) && defined(IP_RECVPKTINFO) && defined(USE_V4_PKTINFO)
|
|
|
|
{
|
|
|
|
/* We retrieve the ifindex from the unused hfrom variable */
|
|
|
|
unsigned int ifindex;
|
|
|
|
|
|
|
|
memcpy(&ifindex, hfrom.hbuf, sizeof (ifindex));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Seek forward from the first interface to find the matching
|
|
|
|
* source interface by interface index.
|
|
|
|
*/
|
|
|
|
ip = interfaces;
|
|
|
|
while ((ip != NULL) && (if_nametoindex(ip->name) != ifindex))
|
|
|
|
ip = ip->next;
|
|
|
|
if (ip == NULL)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
1998-11-06 00:19:56 +00:00
|
|
|
if (bootp_packet_handler) {
|
|
|
|
ifrom.len = 4;
|
|
|
|
memcpy (ifrom.iabuf, &from.sin_addr, ifrom.len);
|
|
|
|
|
1999-10-07 06:36:35 +00:00
|
|
|
(*bootp_packet_handler) (ip, &u.packet, (unsigned)result,
|
1998-11-06 00:19:56 +00:00
|
|
|
from.sin_port, ifrom, &hfrom);
|
|
|
|
}
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
/* If there is buffered data, read again. This is for, e.g.,
|
|
|
|
bpf, which may return two packets at once. */
|
|
|
|
if (ip -> rbuf_offset != ip -> rbuf_len)
|
|
|
|
goto again;
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2007-05-08 23:05:22 +00:00
|
|
|
isc_result_t
|
|
|
|
got_one_v6(omapi_object_t *h) {
|
|
|
|
struct sockaddr_in6 from;
|
|
|
|
struct in6_addr to;
|
|
|
|
struct iaddr ifrom;
|
|
|
|
int result;
|
|
|
|
char buf[65536]; /* maximum size for a UDP packet is 65536 */
|
|
|
|
struct interface_info *ip;
|
|
|
|
int is_unicast;
|
2008-08-29 17:48:57 +00:00
|
|
|
unsigned int if_idx = 0;
|
2007-05-08 23:05:22 +00:00
|
|
|
|
|
|
|
if (h->type != dhcp_type_interface) {
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
|
|
|
ip = (struct interface_info *)h;
|
|
|
|
|
2007-07-13 06:43:43 +00:00
|
|
|
result = receive_packet6(ip, (unsigned char *)buf, sizeof(buf),
|
2008-08-29 17:48:57 +00:00
|
|
|
&from, &to, &if_idx);
|
2007-05-08 23:05:22 +00:00
|
|
|
if (result < 0) {
|
|
|
|
log_error("receive_packet6() failed on %s: %m", ip->name);
|
|
|
|
return ISC_R_UNEXPECTED;
|
|
|
|
}
|
|
|
|
|
2008-08-29 17:48:57 +00:00
|
|
|
/* 0 is 'any' interface. */
|
|
|
|
if (if_idx == 0)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
if (dhcpv6_packet_handler != NULL) {
|
|
|
|
/*
|
|
|
|
* If a packet is not multicast, we assume it is unicast.
|
|
|
|
*/
|
|
|
|
if (IN6_IS_ADDR_MULTICAST(&to)) {
|
|
|
|
is_unicast = ISC_FALSE;
|
|
|
|
} else {
|
|
|
|
is_unicast = ISC_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
ifrom.len = 16;
|
|
|
|
memcpy(ifrom.iabuf, &from.sin6_addr, ifrom.len);
|
|
|
|
|
2008-08-29 17:48:57 +00:00
|
|
|
/* Seek forward to find the matching source interface. */
|
2011-06-27 16:00:32 +00:00
|
|
|
ip = interfaces;
|
2008-08-29 17:48:57 +00:00
|
|
|
while ((ip != NULL) && (if_nametoindex(ip->name) != if_idx))
|
|
|
|
ip = ip->next;
|
|
|
|
|
|
|
|
if (ip == NULL)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
2007-05-08 23:05:22 +00:00
|
|
|
(*dhcpv6_packet_handler)(ip, buf,
|
|
|
|
result, from.sin6_port,
|
|
|
|
&ifrom, is_unicast);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2007-05-08 23:05:22 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_set_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_typed_data_t *value)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *interface;
|
|
|
|
isc_result_t status;
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
if (h -> type != dhcp_type_interface)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
|
|
|
if (!omapi_ds_strcmp (name, "name")) {
|
|
|
|
if ((value -> type == omapi_datatype_data ||
|
|
|
|
value -> type == omapi_datatype_string) &&
|
|
|
|
value -> u.buffer.len < sizeof interface -> name) {
|
|
|
|
memcpy (interface -> name,
|
|
|
|
value -> u.buffer.value,
|
|
|
|
value -> u.buffer.len);
|
|
|
|
interface -> name [value -> u.buffer.len] = 0;
|
|
|
|
} else
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find some inner object that can take the value. */
|
|
|
|
if (h -> inner && h -> inner -> type -> set_value) {
|
|
|
|
status = ((*(h -> inner -> type -> set_value))
|
|
|
|
(h -> inner, id, name, value));
|
2009-10-28 04:12:30 +00:00
|
|
|
if (status == ISC_R_SUCCESS || status == DHCP_R_UNCHANGED)
|
2000-12-28 23:14:46 +00:00
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
isc_result_t dhcp_interface_get_value (omapi_object_t *h,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_data_string_t *name,
|
|
|
|
omapi_value_t **value)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_NOTIMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
|
|
|
isc_result_t dhcp_interface_destroy (omapi_object_t *h,
|
|
|
|
const char *file, int line)
|
|
|
|
{
|
|
|
|
struct interface_info *interface;
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
if (h -> type != dhcp_type_interface)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
if (interface -> ifp) {
|
2000-12-28 23:14:46 +00:00
|
|
|
dfree (interface -> ifp, file, line);
|
2001-06-27 00:31:20 +00:00
|
|
|
interface -> ifp = 0;
|
|
|
|
}
|
|
|
|
if (interface -> next)
|
|
|
|
interface_dereference (&interface -> next, file, line);
|
|
|
|
if (interface -> rbuf) {
|
|
|
|
dfree (interface -> rbuf, file, line);
|
|
|
|
interface -> rbuf = (unsigned char *)0;
|
|
|
|
}
|
|
|
|
if (interface -> client)
|
|
|
|
interface -> client = (struct client_state *)0;
|
|
|
|
|
|
|
|
if (interface -> shared_network)
|
|
|
|
omapi_object_dereference ((omapi_object_t **)
|
|
|
|
&interface -> shared_network, MDL);
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_SUCCESS;
|
1999-09-08 01:44:08 +00:00
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_signal_handler (omapi_object_t *h,
|
|
|
|
const char *name, va_list ap)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *ip, *interface;
|
|
|
|
isc_result_t status;
|
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
2001-04-05 20:50:19 +00:00
|
|
|
/* If it's an update signal, see if the interface is dead right
|
|
|
|
now, or isn't known at all, and if that's the case, revive it. */
|
|
|
|
if (!strcmp (name, "update")) {
|
|
|
|
for (ip = dummy_interfaces; ip; ip = ip -> next)
|
|
|
|
if (ip == interface)
|
|
|
|
break;
|
|
|
|
if (ip && dhcp_interface_startup_hook)
|
|
|
|
return (*dhcp_interface_startup_hook) (ip);
|
2000-12-28 23:14:46 +00:00
|
|
|
|
2001-04-05 20:50:19 +00:00
|
|
|
for (ip = interfaces; ip; ip = ip -> next)
|
|
|
|
if (ip == interface)
|
|
|
|
break;
|
|
|
|
if (!ip && dhcp_interface_startup_hook)
|
|
|
|
return (*dhcp_interface_startup_hook) (ip);
|
2000-12-28 23:14:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to find some inner object that can take the value. */
|
2009-09-09 19:05:17 +00:00
|
|
|
if (h -> inner && h -> inner -> type -> signal_handler) {
|
2000-12-28 23:14:46 +00:00
|
|
|
status = ((*(h -> inner -> type -> signal_handler))
|
|
|
|
(h -> inner, name, ap));
|
|
|
|
if (status == ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_stuff_values (omapi_object_t *c,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_object_t *h)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
struct interface_info *interface;
|
|
|
|
isc_result_t status;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
|
|
|
if (h -> type != dhcp_type_interface)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
interface = (struct interface_info *)h;
|
|
|
|
|
|
|
|
/* Write out all the values. */
|
|
|
|
|
|
|
|
status = omapi_connection_put_name (c, "state");
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
2006-11-07 23:40:14 +00:00
|
|
|
if ((interface->flags & INTERFACE_REQUESTED) != 0)
|
2000-12-28 23:14:46 +00:00
|
|
|
status = omapi_connection_put_string (c, "up");
|
|
|
|
else
|
|
|
|
status = omapi_connection_put_string (c, "down");
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Write out the inner object, if any. */
|
|
|
|
if (h -> inner && h -> inner -> type -> stuff_values) {
|
|
|
|
status = ((*(h -> inner -> type -> stuff_values))
|
|
|
|
(c, id, h -> inner));
|
|
|
|
if (status == ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
}
|
|
|
|
|
1999-09-08 01:44:08 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_lookup (omapi_object_t **ip,
|
|
|
|
omapi_object_t *id,
|
|
|
|
omapi_object_t *ref)
|
1999-09-08 01:44:08 +00:00
|
|
|
{
|
2000-12-28 23:14:46 +00:00
|
|
|
omapi_value_t *tv = (omapi_value_t *)0;
|
|
|
|
isc_result_t status;
|
|
|
|
struct interface_info *interface;
|
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
if (!ref)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_NOKEYS;
|
2001-06-27 00:31:20 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
/* First see if we were sent a handle. */
|
|
|
|
status = omapi_get_value_str (ref, id, "handle", &tv);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
|
|
|
status = omapi_handle_td_lookup (ip, tv -> value);
|
|
|
|
|
|
|
|
omapi_value_dereference (&tv, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
|
|
|
|
/* Don't return the object if the type is wrong. */
|
|
|
|
if ((*ip) -> type != dhcp_type_interface) {
|
|
|
|
omapi_object_dereference (ip, MDL);
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_INVALIDARG;
|
2000-12-28 23:14:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now look for an interface name. */
|
|
|
|
status = omapi_get_value_str (ref, id, "name", &tv);
|
|
|
|
if (status == ISC_R_SUCCESS) {
|
2001-04-05 20:50:19 +00:00
|
|
|
char *s;
|
|
|
|
unsigned len;
|
2000-12-28 23:14:46 +00:00
|
|
|
for (interface = interfaces; interface;
|
|
|
|
interface = interface -> next) {
|
2001-04-05 20:50:19 +00:00
|
|
|
s = memchr (interface -> name, 0, IFNAMSIZ);
|
|
|
|
if (s)
|
|
|
|
len = s - &interface -> name [0];
|
|
|
|
else
|
|
|
|
len = IFNAMSIZ;
|
|
|
|
if ((tv -> value -> u.buffer.len == len &&
|
|
|
|
!memcmp (interface -> name,
|
|
|
|
(char *)tv -> value -> u.buffer.value,
|
|
|
|
len)))
|
2000-12-28 23:14:46 +00:00
|
|
|
break;
|
|
|
|
}
|
2001-04-05 20:50:19 +00:00
|
|
|
if (!interface) {
|
|
|
|
for (interface = dummy_interfaces;
|
|
|
|
interface; interface = interface -> next) {
|
|
|
|
s = memchr (interface -> name, 0, IFNAMSIZ);
|
|
|
|
if (s)
|
|
|
|
len = s - &interface -> name [0];
|
|
|
|
else
|
|
|
|
len = IFNAMSIZ;
|
|
|
|
if ((tv -> value -> u.buffer.len == len &&
|
|
|
|
!memcmp (interface -> name,
|
|
|
|
(char *)
|
|
|
|
tv -> value -> u.buffer.value,
|
|
|
|
len)))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
omapi_value_dereference (&tv, MDL);
|
|
|
|
if (*ip && *ip != (omapi_object_t *)interface) {
|
|
|
|
omapi_object_dereference (ip, MDL);
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_KEYCONFLICT;
|
2000-12-28 23:14:46 +00:00
|
|
|
} else if (!interface) {
|
|
|
|
if (*ip)
|
|
|
|
omapi_object_dereference (ip, MDL);
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
} else if (!*ip)
|
|
|
|
omapi_object_reference (ip,
|
|
|
|
(omapi_object_t *)interface,
|
|
|
|
MDL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we get to here without finding an interface, no valid key was
|
|
|
|
specified. */
|
|
|
|
if (!*ip)
|
2009-10-28 04:12:30 +00:00
|
|
|
return DHCP_R_NOKEYS;
|
2000-12-28 23:14:46 +00:00
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* actually just go discover the interface */
|
|
|
|
isc_result_t dhcp_interface_create (omapi_object_t **lp,
|
|
|
|
omapi_object_t *id)
|
|
|
|
{
|
|
|
|
struct interface_info *hp;
|
|
|
|
isc_result_t status;
|
1999-09-08 01:44:08 +00:00
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
hp = (struct interface_info *)0;
|
|
|
|
status = interface_allocate (&hp, MDL);
|
|
|
|
if (status != ISC_R_SUCCESS)
|
|
|
|
return status;
|
|
|
|
hp -> flags = INTERFACE_REQUESTED;
|
|
|
|
status = interface_reference ((struct interface_info **)lp, hp, MDL);
|
|
|
|
interface_dereference (&hp, MDL);
|
|
|
|
return status;
|
1998-11-06 00:19:56 +00:00
|
|
|
}
|
|
|
|
|
2000-12-28 23:14:46 +00:00
|
|
|
isc_result_t dhcp_interface_remove (omapi_object_t *lp,
|
|
|
|
omapi_object_t *id)
|
|
|
|
{
|
|
|
|
struct interface_info *interface, *ip, *last;
|
|
|
|
|
|
|
|
interface = (struct interface_info *)lp;
|
|
|
|
|
|
|
|
/* remove from interfaces */
|
|
|
|
last = 0;
|
|
|
|
for (ip = interfaces; ip; ip = ip -> next) {
|
|
|
|
if (ip == interface) {
|
|
|
|
if (last) {
|
|
|
|
interface_dereference (&last -> next, MDL);
|
|
|
|
if (ip -> next)
|
|
|
|
interface_reference (&last -> next,
|
|
|
|
ip -> next, MDL);
|
|
|
|
} else {
|
|
|
|
interface_dereference (&interfaces, MDL);
|
|
|
|
if (ip -> next)
|
|
|
|
interface_reference (&interfaces,
|
|
|
|
ip -> next, MDL);
|
|
|
|
}
|
|
|
|
if (ip -> next)
|
|
|
|
interface_dereference (&ip -> next, MDL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
last = ip;
|
|
|
|
}
|
|
|
|
if (!ip)
|
|
|
|
return ISC_R_NOTFOUND;
|
|
|
|
|
|
|
|
/* add the interface to the dummy_interface list */
|
|
|
|
if (dummy_interfaces) {
|
|
|
|
interface_reference (&interface -> next,
|
|
|
|
dummy_interfaces, MDL);
|
|
|
|
interface_dereference (&dummy_interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&dummy_interfaces, interface, MDL);
|
|
|
|
|
|
|
|
/* do a DHCPRELEASE */
|
|
|
|
if (dhcp_interface_shutdown_hook)
|
|
|
|
(*dhcp_interface_shutdown_hook) (interface);
|
|
|
|
|
|
|
|
/* remove the io object */
|
|
|
|
omapi_unregister_io_object ((omapi_object_t *)interface);
|
|
|
|
|
2009-10-28 04:12:30 +00:00
|
|
|
switch(local_family) {
|
2007-05-19 18:47:15 +00:00
|
|
|
#ifdef DHCPv6
|
2009-10-28 04:12:30 +00:00
|
|
|
case AF_INET6:
|
2007-05-08 23:05:22 +00:00
|
|
|
if_deregister6(interface);
|
2009-10-28 04:12:30 +00:00
|
|
|
break;
|
2007-05-19 18:47:15 +00:00
|
|
|
#endif /* DHCPv6 */
|
2009-10-28 04:12:30 +00:00
|
|
|
case AF_INET:
|
|
|
|
default:
|
|
|
|
if_deregister_send(interface);
|
|
|
|
if_deregister_receive(interface);
|
|
|
|
break;
|
2007-05-08 23:05:22 +00:00
|
|
|
}
|
2000-12-28 23:14:46 +00:00
|
|
|
|
|
|
|
return ISC_R_SUCCESS;
|
|
|
|
}
|
2001-02-12 19:40:05 +00:00
|
|
|
|
|
|
|
void interface_stash (struct interface_info *tptr)
|
|
|
|
{
|
|
|
|
struct interface_info **vec;
|
|
|
|
int delta;
|
|
|
|
|
|
|
|
/* If the registerer didn't assign an index, assign one now. */
|
|
|
|
if (tptr -> index == -1) {
|
|
|
|
tptr -> index = interface_count++;
|
|
|
|
while (tptr -> index < interface_max &&
|
|
|
|
interface_vector [tptr -> index])
|
|
|
|
tptr -> index = interface_count++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (interface_max <= tptr -> index) {
|
|
|
|
delta = tptr -> index - interface_max + 10;
|
|
|
|
vec = dmalloc ((interface_max + delta) *
|
|
|
|
sizeof (struct interface_info *), MDL);
|
2017-06-20 06:56:52 -04:00
|
|
|
if (!vec) {
|
|
|
|
log_error ("interface_stash: allocation failed ");
|
2001-02-12 19:40:05 +00:00
|
|
|
return;
|
2017-06-20 06:56:52 -04:00
|
|
|
}
|
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
memset (&vec [interface_max], 0,
|
|
|
|
(sizeof (struct interface_info *)) * delta);
|
|
|
|
interface_max += delta;
|
|
|
|
if (interface_vector) {
|
|
|
|
memcpy (vec, interface_vector,
|
|
|
|
(interface_count *
|
|
|
|
sizeof (struct interface_info *)));
|
|
|
|
dfree (interface_vector, MDL);
|
|
|
|
}
|
2017-06-20 06:56:52 -04:00
|
|
|
|
2001-02-12 19:40:05 +00:00
|
|
|
interface_vector = vec;
|
|
|
|
}
|
2017-06-20 06:56:52 -04:00
|
|
|
|
2001-06-27 00:31:20 +00:00
|
|
|
interface_reference (&interface_vector [tptr -> index], tptr, MDL);
|
2001-02-12 19:40:05 +00:00
|
|
|
if (tptr -> index >= interface_count)
|
|
|
|
interface_count = tptr -> index + 1;
|
|
|
|
#if defined (TRACING)
|
|
|
|
trace_interface_register (interface_trace, tptr);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void interface_snorf (struct interface_info *tmp, int ir)
|
|
|
|
{
|
|
|
|
tmp -> circuit_id = (u_int8_t *)tmp -> name;
|
|
|
|
tmp -> circuit_id_len = strlen (tmp -> name);
|
|
|
|
tmp -> remote_id = 0;
|
|
|
|
tmp -> remote_id_len = 0;
|
|
|
|
tmp -> flags = ir;
|
|
|
|
if (interfaces) {
|
|
|
|
interface_reference (&tmp -> next,
|
|
|
|
interfaces, MDL);
|
|
|
|
interface_dereference (&interfaces, MDL);
|
|
|
|
}
|
|
|
|
interface_reference (&interfaces, tmp, MDL);
|
|
|
|
}
|