/* dnsmasq is Copyright (c) 2000-2009 Simon Kelley

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; version 2 dated June, 1991, or
   (at your option) version 3 dated 29 June, 2007.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#define COPYRIGHT "Copyright (C) 2000-2009 Simon Kelley"

#ifndef NO_LARGEFILE
/* Ensure we can use files >2GB (log files may grow this big) */
#define _LARGEFILE_SOURCE 1
#define _FILE_OFFSET_BITS 64
#endif

/* Get linux C library versions. */
#ifdef __linux__
#ifndef __ANDROID__
#define _GNU_SOURCE
#endif
#include <features.h>
#endif

/* get these before config.h  for IPv6 stuff... */
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/types.h>

#ifdef __APPLE__
#include <arpa/nameser_compat.h>
#include <nameser.h>
#else
#ifdef __ANDROID__
#include "nameser.h"
#else
#include <arpa/nameser.h>
#endif
#endif

/* and this. */
#include <getopt.h>

#include "config.h"

#define gettext_noop(S) (S)
#ifndef LOCALEDIR
#define _(S) (S)
#else
#include <libintl.h>
#include <locale.h>
#define _(S) gettext(S)
#endif

#include <arpa/inet.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <limits.h>
#include <net/if.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
#if defined(__OpenBSD__) || defined(__NetBSD__) || defined(__sun__) || defined(__sun) || \
    defined(__ANDROID__)
#include <netinet/if_ether.h>
#else
#include <net/ethernet.h>
#endif
#include <dirent.h>
#include <net/if_arp.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/ip_icmp.h>
#include <sys/uio.h>
#include <syslog.h>
#ifndef HAVE_LINUX_NETWORK
#include <net/if_dl.h>
#endif

#if defined(HAVE_LINUX_NETWORK)
#include <linux/capability.h>
/* There doesn't seem to be a universally-available
   userpace header for these. */
extern int capset(cap_user_header_t header, cap_user_data_t data);
extern int capget(cap_user_header_t header, cap_user_data_t data);
#define LINUX_CAPABILITY_VERSION_1 0x19980330
#define LINUX_CAPABILITY_VERSION_2 0x20071026
#define LINUX_CAPABILITY_VERSION_3 0x20080522

#include <sys/prctl.h>
#endif

/* daemon is function in the C library.... */
#define daemon dnsmasq_daemon

/* Async event queue */
struct event_desc {
    int event, data;
};

#define EVENT_RELOAD 1
#define EVENT_DUMP 2
#define EVENT_ALARM 3
#define EVENT_TERM 4
#define EVENT_CHILD 5
#define EVENT_REOPEN 6
#define EVENT_EXITED 7
#define EVENT_KILLED 8
#define EVENT_EXEC_ERR 9
#define EVENT_PIPE_ERR 10
#define EVENT_USER_ERR 11
#define EVENT_CAP_ERR 12
#define EVENT_PIDFILE 13
#define EVENT_HUSER_ERR 14
#define EVENT_GROUP_ERR 15
#define EVENT_DIE 16
#define EVENT_LOG_ERR 17
#define EVENT_FORK_ERR 18

/* Exit codes. */
#define EC_GOOD 0
#define EC_BADCONF 1
#define EC_BADNET 2
#define EC_FILE 3
#define EC_NOMEM 4
#define EC_MISC 5
#define EC_INIT_OFFSET 10

/* Min buffer size: we check after adding each record, so there must be
   memory for the largest packet, and the largest record so the
   min for DNS is PACKETSZ+MAXDNAME+RRFIXEDSZ which is < 1000.
   This might be increased is EDNS packet size if greater than the minimum.
*/
#define DNSMASQ_PACKETSZ PACKETSZ + MAXDNAME + RRFIXEDSZ

#define OPT_BOGUSPRIV (1u << 0)
#define OPT_FILTER (1u << 1)
#define OPT_LOG (1u << 2)
#define OPT_SELFMX (1u << 3)
#define OPT_NO_HOSTS (1u << 4)
#define OPT_NO_POLL (1u << 5)
#define OPT_DEBUG (1u << 6)
#define OPT_ORDER (1u << 7)
#define OPT_NO_RESOLV (1u << 8)
#define OPT_EXPAND (1u << 9)
#define OPT_LOCALMX (1u << 10)
#define OPT_NO_NEG (1u << 11)
#define OPT_NODOTS_LOCAL (1u << 12)
#define OPT_NOWILD (1u << 13)
#define OPT_RESOLV_DOMAIN (1u << 15)
#define OPT_NO_FORK (1u << 16)
#define OPT_AUTHORITATIVE (1u << 17)
#define OPT_LOCALISE (1u << 18)
#define OPT_DBUS (1u << 19)
#define OPT_DHCP_FQDN (1u << 20)
#define OPT_NO_PING (1u << 21)
#define OPT_LEASE_RO (1u << 22)
#define OPT_ALL_SERVERS (1u << 23)
#define OPT_RELOAD (1u << 24)
#define OPT_TFTP (1u << 25)
#define OPT_TFTP_SECURE (1u << 26)
#define OPT_TFTP_NOBLOCK (1u << 27)
#define OPT_LOG_OPTS (1u << 28)
#define OPT_TFTP_APREF (1u << 29)
#define OPT_NO_OVERRIDE (1u << 30)
#define OPT_NO_REBIND (1u << 31)

/* extra flags for my_syslog, we use a couple of facilities since they are known
   not to occupy the same bits as priorities, no matter how syslog.h is set up. */
#define MS_TFTP LOG_USER
#define MS_DHCP LOG_DAEMON

struct all_addr {
    union {
        struct in_addr addr4;
#ifdef HAVE_IPV6
        struct in6_addr addr6;
#endif
    } addr;
};

struct bogus_addr {
    struct in_addr addr;
    struct bogus_addr* next;
};

/* dns doctor param */
struct doctor {
    struct in_addr in, end, out, mask;
    struct doctor* next;
};

struct mx_srv_record {
    char *name, *target;
    int issrv, srvport, priority, weight;
    unsigned int offset;
    struct mx_srv_record* next;
};

struct naptr {
    char *name, *replace, *regexp, *services, *flags;
    unsigned int order, pref;
    struct naptr* next;
};

struct txt_record {
    char *name, *txt;
    unsigned short class, len;
    struct txt_record* next;
};

struct ptr_record {
    char *name, *ptr;
    struct ptr_record* next;
};

struct cname {
    char *alias, *target;
    struct cname* next;
};

struct interface_name {
    char* name; /* domain name */
    char* intr; /* interface name */
    struct interface_name* next;
};

union bigname {
    char name[MAXDNAME];
    union bigname* next; /* freelist */
};

struct crec {
    struct crec *next, *prev, *hash_next;
    time_t ttd; /* time to die */
    int uid;
    union {
        struct all_addr addr;
        struct {
            struct crec* cache;
            int uid;
        } cname;
    } addr;
    unsigned short flags;
    union {
        char sname[SMALLDNAME];
        union bigname* bname;
        char* namep;
    } name;
};

#define F_IMMORTAL 1
#define F_CONFIG 2
#define F_REVERSE 4
#define F_FORWARD 8
#define F_DHCP 16
#define F_NEG 32
#define F_HOSTS 64
#define F_IPV4 128
#define F_IPV6 256
#define F_BIGNAME 512
#define F_UPSTREAM 1024
#define F_SERVER 2048
#define F_NXDOMAIN 4096
#define F_QUERY 8192
#define F_CNAME 16384
#define F_NOERR 32768

/* struct sockaddr is not large enough to hold any address,
   and specifically not big enough to hold an IPv6 address.
   Blech. Roll our own. */
union mysockaddr {
    struct sockaddr sa;
    struct sockaddr_in in;
#if defined(HAVE_IPV6)
    struct sockaddr_in6 in6;
#endif
};

#define SERV_FROM_RESOLV 1       /* 1 for servers from resolv, 0 for command line. */
#define SERV_NO_ADDR 2           /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4   /* addr is the answer, not the server */
#define SERV_HAS_DOMAIN 8        /* server for one domain only */
#define SERV_HAS_SOURCE 16       /* source address defined */
#define SERV_FOR_NODOTS 32       /* server for names with no domain part only */
#define SERV_WARNED_RECURSIVE 64 /* avoid warning spam */
#define SERV_FROM_DBUS 128       /* 1 if source is DBus */
#define SERV_MARK 256            /* for mark-and-delete */
#define SERV_TYPE (SERV_HAS_DOMAIN | SERV_FOR_NODOTS)
#define SERV_COUNTED 512 /* workspace for log code */

struct serverfd {
    int fd;
    union mysockaddr source_addr;
    char interface[IF_NAMESIZE + 1];
    struct serverfd* next;
    uint32_t mark;
};

struct randfd {
    int fd;
    unsigned short refcount, family;
};

struct server {
    union mysockaddr addr, source_addr;
    char interface[IF_NAMESIZE + 1];
    struct serverfd* sfd;
    char* domain; /* set if this server only handles a domain. */
    int flags, tcpfd;
    unsigned int queries, failed_queries;
    uint32_t mark;
    struct server* next;
};

struct irec {
    union mysockaddr addr;
    struct in_addr netmask; /* only valid for IPv4 */
    int dhcp_ok, mtu;
    struct irec* next;
};

struct listener {
    int fd, tcpfd, family;
    struct irec* iface; /* only valid for non-wildcard */
    struct listener* next;
};

/* interface and address parms from command line. */
struct iname {
    char* name;
    union mysockaddr addr;
    int isloop, used;
    struct iname* next;
};

/* resolv-file parms from command-line */
struct resolvc {
    struct resolvc* next;
    int is_default, logged;
    time_t mtime;
    char* name;
};

/* adn-hosts parms from command-line */
#define AH_DIR 1
#define AH_INACTIVE 2
struct hostsfile {
    struct hostsfile* next;
    int flags;
    char* fname;
    int index; /* matches to cache entries for logging */
};

struct frec {
    union mysockaddr source;
    struct all_addr dest;
    struct server* sentto; /* NULL means free */
    struct randfd* rfd4;
#ifdef HAVE_IPV6
    struct randfd* rfd6;
#endif
    unsigned int iface;
    unsigned short orig_id, new_id;
    int fd, forwardall;
    unsigned int crc;
    time_t time;
    struct frec* next;
};

/* actions in the daemon->helper RPC */
#define ACTION_DEL 1
#define ACTION_OLD_HOSTNAME 2
#define ACTION_OLD 3
#define ACTION_ADD 4

#define DHCP_CHADDR_MAX 16

struct dhcp_lease {
    int clid_len;          /* length of client identifier */
    unsigned char* clid;   /* clientid */
    char *hostname, *fqdn; /* name from client-hostname option or config */
    char* old_hostname;    /* hostname before it moved to another lease */
    char auth_name;        /* hostname came from config, not from client */
    char new;              /* newly created */
    char changed;          /* modified */
    char aux_changed;      /* CLID or expiry changed */
    time_t expires;        /* lease expiry */
#ifdef HAVE_BROKEN_RTC
    unsigned int length;
#endif
    int hwaddr_len, hwaddr_type;
    unsigned char hwaddr[DHCP_CHADDR_MAX];
    struct in_addr addr, override, giaddr;
    unsigned char *vendorclass, *userclass, *supplied_hostname;
    unsigned int vendorclass_len, userclass_len, supplied_hostname_len;
    int last_interface;
    struct dhcp_lease* next;
};

struct dhcp_netid {
    char* net;
    struct dhcp_netid* next;
};

struct dhcp_netid_list {
    struct dhcp_netid* list;
    struct dhcp_netid_list* next;
};

struct hwaddr_config {
    int hwaddr_len, hwaddr_type;
    unsigned char hwaddr[DHCP_CHADDR_MAX];
    unsigned int wildcard_mask;
    struct hwaddr_config* next;
};

struct dhcp_config {
    unsigned int flags;
    int clid_len;        /* length of client identifier */
    unsigned char* clid; /* clientid */
    char *hostname, *domain;
    struct dhcp_netid netid;
    struct in_addr addr;
    time_t decline_time;
    unsigned int lease_time;
    struct hwaddr_config* hwaddr;
    struct dhcp_config* next;
};

#define CONFIG_DISABLE 1
#define CONFIG_CLID 2
#define CONFIG_TIME 8
#define CONFIG_NAME 16
#define CONFIG_ADDR 32
#define CONFIG_NETID 64
#define CONFIG_NOCLID 128
#define CONFIG_ADDR_HOSTS 512 /* address added by from /etc/hosts */
#define CONFIG_DECLINED 1024  /* address declined by client */
#define CONFIG_BANK 2048      /* from dhcp hosts file */

struct dhcp_opt {
    int opt, len, flags;
    union {
        int encap;
        unsigned int wildcard_mask;
        unsigned char* vendor_class;
    } u;
    unsigned char* val;
    struct dhcp_netid* netid;
    struct dhcp_opt* next;
};

#define DHOPT_ADDR 1
#define DHOPT_STRING 2
#define DHOPT_ENCAPSULATE 4
#define DHOPT_ENCAP_MATCH 8
#define DHOPT_FORCE 16
#define DHOPT_BANK 32
#define DHOPT_ENCAP_DONE 64
#define DHOPT_MATCH 128
#define DHOPT_VENDOR 256
#define DHOPT_HEX 512
#define DHOPT_VENDOR_MATCH 1024

struct dhcp_boot {
    char *file, *sname;
    struct in_addr next_server;
    struct dhcp_netid* netid;
    struct dhcp_boot* next;
};

struct pxe_service {
    unsigned short CSA, type;
    char *menu, *basename;
    struct in_addr server;
    struct dhcp_netid* netid;
    struct pxe_service* next;
};

#define MATCH_VENDOR 1
#define MATCH_USER 2
#define MATCH_CIRCUIT 3
#define MATCH_REMOTE 4
#define MATCH_SUBSCRIBER 5

/* vendorclass, userclass, remote-id or cicuit-id */
struct dhcp_vendor {
    int len, match_type, option;
    char* data;
    struct dhcp_netid netid;
    struct dhcp_vendor* next;
};

struct dhcp_mac {
    unsigned int mask;
    int hwaddr_len, hwaddr_type;
    unsigned char hwaddr[DHCP_CHADDR_MAX];
    struct dhcp_netid netid;
    struct dhcp_mac* next;
};

struct dhcp_bridge {
    char iface[IF_NAMESIZE];
    struct dhcp_bridge *alias, *next;
};

struct cond_domain {
    char* domain;
    struct in_addr start, end;
    struct cond_domain* next;
};

struct dhcp_context {
    unsigned int lease_time, addr_epoch;
    struct in_addr netmask, broadcast;
    struct in_addr local, router;
    struct in_addr start, end; /* range of available addresses */
    int flags;
    struct dhcp_netid netid, *filter;
    struct dhcp_context *next, *current;
};

#define CONTEXT_STATIC 1
#define CONTEXT_NETMASK 2
#define CONTEXT_BRDCAST 4
#define CONTEXT_PROXY 8

typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;

struct dhcp_packet {
    u8 op, htype, hlen, hops;
    u32 xid;
    u16 secs, flags;
    struct in_addr ciaddr, yiaddr, siaddr, giaddr;
    u8 chaddr[DHCP_CHADDR_MAX], sname[64], file[128];
    u8 options[312];
};

struct ping_result {
    struct in_addr addr;
    time_t time;
    struct ping_result* next;
};

extern struct daemon {
    /* datastuctures representing the command-line and
       config file arguments. All set (including defaults)
       in option.c */

    unsigned int options;
    struct resolvc default_resolv, *resolv_files;
    time_t last_resolv;
    struct mx_srv_record* mxnames;
    struct naptr* naptr;
    struct txt_record* txt;
    struct ptr_record* ptr;
    struct cname* cnames;
    struct interface_name* int_names;
    char* mxtarget;
    char* lease_file;
    char *username, *groupname, *scriptuser;
    int group_set, osport;
    char* domain_suffix;
    struct cond_domain* cond_domain;
    char* runfile;
    char* lease_change_command;
    struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
    struct bogus_addr* bogus_addr;
    struct server* servers;
    int log_fac;    /* log facility */
    char* log_file; /* optional log file */
    int max_logs;   /* queue limit */
    int cachesize, ftabsize;
    int port, query_port, min_port;
    unsigned long local_ttl, neg_ttl;
    struct hostsfile* addn_hosts;
    struct dhcp_context* dhcp;
    struct dhcp_config* dhcp_conf;
    struct dhcp_opt *dhcp_opts, *dhcp_match;
    struct dhcp_vendor* dhcp_vendors;
    struct dhcp_mac* dhcp_macs;
    struct dhcp_boot* boot_config;
    struct pxe_service* pxe_services;
    int enable_pxe;
    struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *force_broadcast, *bootp_dynamic;
    char *dhcp_hosts_file, *dhcp_opts_file;
    int dhcp_max;
    int dhcp_server_port, dhcp_client_port;
    unsigned int min_leasetime;
    struct doctor* doctors;
    unsigned short edns_pktsz;
    uint32_t listen_mark;

    /* globally used stuff for DNS */
    char* packet;       /* packet buffer */
    int packet_buff_sz; /* size of above */
    char* namebuff;     /* MAXDNAME size buffer */
    unsigned int local_answer, queries_forwarded;
    struct frec* frec_list;
    struct serverfd* sfds;
    struct irec* interfaces;
    struct listener* listeners;
    struct server* last_server;
    time_t forwardtime;
    int forwardcount;
    struct server* srv_save; /* Used for resend on DoD */
    size_t packet_len;       /*      "        "        */
    struct randfd* rfd_save; /*      "        "        */
    pid_t tcp_pids[MAX_PROCS];
    struct randfd randomsocks[RANDOM_SOCKS];

    /* DHCP state */
    int dhcpfd, helperfd;
    int netlinkfd;
    struct iovec dhcp_packet;
    char *dhcp_buff, *dhcp_buff2;
    struct ping_result* ping_results;
    FILE* lease_stream;
    struct dhcp_bridge* bridges;

} * daemon;

/* cache.c */
void cache_init(void);
void log_query(unsigned short flags, char* name, struct all_addr* addr, char* arg);
char* record_source(int index);
void querystr(char* str, unsigned short type);
struct crec* cache_find_by_addr(struct crec* crecp, struct all_addr* addr, time_t now,
                                unsigned short prot);
struct crec* cache_find_by_name(struct crec* crecp, char* name, time_t now, unsigned short prot);
void cache_end_insert(void);
void cache_start_insert(void);
struct crec* cache_insert(char* name, struct all_addr* addr, time_t now, unsigned long ttl,
                          unsigned short flags);
void cache_reload(void);
void cache_add_dhcp_entry(char* host_name, struct in_addr* host_address, time_t ttd);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
char* cache_get_name(struct crec* crecp);
char* get_domain(struct in_addr addr);

/* rfc1035.c */
unsigned short extract_request(HEADER* header, size_t qlen, char* name, unsigned short* typep);
size_t setup_reply(HEADER* header, size_t qlen, struct all_addr* addrp, unsigned short flags,
                   unsigned long local_ttl);
int extract_addresses(HEADER* header, size_t qlen, char* namebuff, time_t now);
size_t answer_request(HEADER* header, char* limit, size_t qlen, struct in_addr local_addr,
                      struct in_addr local_netmask, time_t now);
int check_for_bogus_wildcard(HEADER* header, size_t qlen, char* name, struct bogus_addr* addr,
                             time_t now);
unsigned char* find_pseudoheader(HEADER* header, size_t plen, size_t* len, unsigned char** p,
                                 int* is_sign);
int check_for_local_domain(char* name, time_t now);
unsigned int questions_crc(HEADER* header, size_t plen, char* buff);
size_t resize_packet(HEADER* header, size_t plen, unsigned char* pheader, size_t hlen);

/* util.c */
void rand_init(void);
unsigned short rand16(void);
int legal_hostname(char* c);
char* canonicalise(char* s, int* nomem);
unsigned char* do_rfc1035_name(unsigned char* p, char* sval, char *limit);
void* safe_malloc(size_t size);
void safe_pipe(int* fd, int read_noblock);
void* whine_malloc(size_t size);
int sa_len(union mysockaddr* addr);
int sockaddr_isequal(union mysockaddr* s1, union mysockaddr* s2);
int hostname_isequal(char* a, char* b);
time_t dnsmasq_time(void);
int is_same_net(struct in_addr a, struct in_addr b, struct in_addr mask);
int retry_send(void);
int parse_addr(int family, const char* addrstr, union mysockaddr* addr);
void prettyprint_time(char* buf, unsigned int t);
int prettyprint_addr(const union mysockaddr* addr, char* buf);
int parse_hex(char* in, unsigned char* out, int maxlen, unsigned int* wildcard_mask, int* mac_type);
int memcmp_masked(unsigned char* a, unsigned char* b, int len, unsigned int mask);
int expand_buf(struct iovec* iov, size_t size);
char* print_mac(char* buff, unsigned char* mac, int len);
void bump_maxfd(int fd, int* max);
int read_write(int fd, unsigned char* packet, int size, int rw);

/* log.c */
void die(char* message, char* arg1, int exit_code);
int log_start(struct passwd* ent_pw, int errfd);
int log_reopen(char* log_file);
void my_syslog(int priority, const char* format, ...);
void set_log_writer(fd_set* set, int* maxfdp);
void check_log_writer(fd_set* set);
void flush_log(void);

/* option.c */
void read_opts(int argc, char** argv, char* compile_opts);
char* option_string(unsigned char opt, int* is_ip, int* is_name);
void reread_dhcp(void);

/* forward.c */
void reply_query(int fd, int family, time_t now);
void receive_query(struct listener* listen, time_t now);
unsigned char* tcp_request(int confd, time_t now, struct in_addr local_addr, struct in_addr netmask);
void server_gone(struct server* server);
struct frec* get_new_frec(time_t now, int* wait);

/* network.c */
int indextoname(int fd, int index, char* name);
int local_bind(int fd, union mysockaddr* addr, char* intname, uint32_t mark, int is_tcp);
int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char* fname);
#ifdef __ANDROID__
int set_servers(const char* servers);
void set_interfaces(const char* interfaces);
#endif
void check_servers(void);
int enumerate_interfaces();
struct listener* create_wildcard_listeners(void);
struct listener* create_bound_listeners(void);
int iface_check(int family, struct all_addr* addr, char* name, int* indexp);
int fix_fd(int fd);
struct in_addr get_ifaddr(char* intr);

/* dhcp.c */
#ifdef HAVE_DHCP
void dhcp_init(void);
void dhcp_packet(time_t now);
struct dhcp_context* address_available(struct dhcp_context* context, struct in_addr addr,
                                       struct dhcp_netid* netids);
struct dhcp_context* narrow_context(struct dhcp_context* context, struct in_addr taddr,
                                    struct dhcp_netid* netids);
int match_netid(struct dhcp_netid* check, struct dhcp_netid* pool, int negonly);
int address_allocate(struct dhcp_context* context, struct in_addr* addrp, unsigned char* hwaddr,
                     int hw_len, struct dhcp_netid* netids, time_t now);
int config_has_mac(struct dhcp_config* config, unsigned char* hwaddr, int len, int type);
struct dhcp_config* find_config(struct dhcp_config* configs, struct dhcp_context* context,
                                unsigned char* clid, int clid_len, unsigned char* hwaddr,
                                int hw_len, int hw_type, char* hostname);
void dhcp_update_configs(struct dhcp_config* configs);
void check_dhcp_hosts(int fatal);
struct dhcp_config* config_find_by_address(struct dhcp_config* configs, struct in_addr addr);
char* strip_hostname(char* hostname);
char* host_from_dns(struct in_addr addr);
char* get_domain(struct in_addr addr);
#endif

/* lease.c */
#ifdef HAVE_DHCP
void lease_update_file(time_t now);
void lease_update_dns();
void lease_init(time_t now);
struct dhcp_lease* lease_allocate(struct in_addr addr);
void lease_set_hwaddr(struct dhcp_lease* lease, unsigned char* hwaddr, unsigned char* clid,
                      int hw_len, int hw_type, int clid_len);
void lease_set_hostname(struct dhcp_lease* lease, char* name, int auth);
void lease_set_expires(struct dhcp_lease* lease, unsigned int len, time_t now);
void lease_set_interface(struct dhcp_lease* lease, int interface);
struct dhcp_lease* lease_find_by_client(unsigned char* hwaddr, int hw_len, int hw_type,
                                        unsigned char* clid, int clid_len);
struct dhcp_lease* lease_find_by_addr(struct in_addr addr);
void lease_prune(struct dhcp_lease* target, time_t now);
void lease_update_from_configs(void);
int do_script_run(time_t now);
void rerun_scripts(void);
#endif

/* rfc2131.c */
#ifdef HAVE_DHCP
size_t dhcp_reply(struct dhcp_context* context, char* iface_name, int int_index, size_t sz,
                  time_t now, int unicast_dest, int* is_inform);
unsigned char* extended_hwaddr(int hwtype, int hwlen, unsigned char* hwaddr, int clid_len,
                               unsigned char* clid, int* len_out);
#endif

/* dnsmasq.c */
#ifdef HAVE_DHCP
int make_icmp_sock(void);
int icmp_ping(struct in_addr addr);
#endif
void send_event(int fd, int event, int data);
void clear_cache_and_reload(time_t now);

/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
void netlink_multicast(void);
#endif

/* bpf.c or netlink.c */
int iface_enumerate(void* parm, int (*ipv4_callback)(), int (*ipv6_callback)());

/* helper.c */
#if defined(HAVE_DHCP) && !defined(NO_FORK)
int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd);
void helper_write(void);
void queue_script(int action, struct dhcp_lease* lease, char* hostname, time_t now);
int helper_buf_empty(void);
#endif
