/* Copyright (c) 2002-2006 Sam Trenholme
 *
 * TERMS
 *
 * 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.
 *
 * This software is provided 'as is' with no guarantees of correctness or
 * fitness for purpose.
 */

#ifndef MARADNSH_DEFINED
#define MARADNSH_DEFINED

/* Franky Van Liedekerke's contributions so this can compile on Solaris */
#ifdef SOLARIS
#ifndef _uint_defined
typedef unsigned int u_int32_t;
typedef unsigned short u_int16_t;
#define _uint_defined
#endif /* _uint_defined */
#define       INADDR_NONE             0xffffffff
#endif /* SOLARIS */

/* Mingw32 */
#ifdef MINGW32
#ifndef _uint_defined
typedef unsigned int u_int32_t;
typedef unsigned short u_int16_t;
typedef short int16_t;
typedef int int32_t;
#define _uint_defined
#endif /* _uint_defined */
#endif /* MINGW32 */

/* Gerrit P. Haase's suggested the following for compiling this on 
   Cygwin */
#ifdef __CYGWIN__
#define MSG_WAITALL 0x40
#endif /* __CYGWIN__ */

/* The maximum allowed size of a zone name */
#define MAX_ZONE_SIZE 256

/* The default UID (User ID) that MaraDNS has; I put this here so packagers 
   can change this easily.  This should be the 'nobody' user, or, optionally
   a special 'MaraDNS' user.  This user needs to be able to enter
   the /etc/maradns directory, and read all zone files in /etc/maradns 

   If you change this from 99, please also change the mararc man page, which
   states the default value for this is 99.  To change the man page:

   * Enter the doc/en/source directory

   * Modify the mararc.ej file

   * Enter the doc/en/man directory
  
   * If you have a recent version of Perl on your system, you should be 
     able to update the man page by typing in 'make'. 

   * Enter the doc/en/tutorial directory

   * Enter the doc/en/tutorial/text directory
 
   * If Bash is at /bin, you should be able to update the text documentation
     by typing in make.  Otherwise, change the tools/ej/ej2txt file's first
     line to point to Bash
 */

#define MARADNS_DEFAULT_UID 99

/* The default GID (Group ID) that MaraDNS has; see the default UID notes
   above.  Again: CHANGE THE MARARC MAN PAGE IF YOU CHANGE THIS VALUE */
#define MARADNS_DEFAULT_GID 99

/* The UID that the Duende logging process uses.  CHANGE THE DUENDE MAN
   PAGE IF YOU CHANGE THIS VALUE (same general process as changing the
   mararc man page; the source file for the duende man page is duende.ej) */
#define DUENDE_LOGGER_UID 66

/* The directory that Duende runs in.  This directory has to exist for
   Duende to be able to run.  Again, IF YOU CHANGE THIS, CHANGE THE
   DUENDE MAN PAGE */
#define DUENDE_CHROOT_DIR "/etc/maradns/logger"

/* The default IP address that Askmara uses; this used to be 127.0.0.3
   but is now 127.0.0.1 because many non-Linux systems only use 127.0.0.1
   for the loopback interface.  IF YOU CHANGE THIS, CHANGE THE ASKMARA
   MAN PAGE (askmara.ej) */
#define ASKMARA_DEFAULT_SERVER "127.0.0.1"

/* The port to bind the DNS server to, and the port that askmara uses 
   to bind to.  Note that a lot of MaraDNS' messages are hard-coded
   to say that we are binding on port 53, so only change this for
   debugging purposes.  I use this so that I can debug MaraDNS on
   systems where I do not have root. */
#define DNS_PORT 53

/* The port to use when contacting remove DNS servers; it may be desirable
 * to have two instances of MaraDNS on the same IP when resolving the 
 * dangling CNAME issue on a machine with only one loopback IP (You would
 * think, with an entire Class A of the IP space reserved for loopback,
 * more systems would have at least two loopback IPs.  You would be wrong)
 */
#define UPSTREAM_PORT 53

/* Whether we allow MaraDNS to run as a non root user; this is usually 
 * disabled, but can be enabled by uncommenting the following line */
/* #define ALLOW_NON_ROOT */

#ifndef JS_STRING_INCLUDED
#include "libs/JsStr.h"
#endif

/* u_int16_t, etc. */
#include <sys/types.h>

/* The encoding for the strings in the configuration files (3: iso 8859-1) */
#define MARA_LOCALE 3

#ifndef MINGW32
/* The data types for 32-bit signed and unsigned data */
#define int32 int32_t
#define uint32 u_int32_t

/* These data types need to store at least 16 bits, and can store more */
#define int16 int16_t
#define uint16 u_int16_t

#else
#define int32 int
#define uint32 unsigned int
#define int16 int
#define uint16 unsigned int
#define MSG_WAITALL 0
#define socklen_t int
#endif /* MINGW32 */

/* The data type used for storing "perm" bits (who gets to view a given 
 * DNS record; based on IP) */
#define perm_t uint16

/* The timestamp which MaraDNS now uses; she is now Y2038-complient
   on (what will be by then) legacy systems with a 32-bit time_t
 */
#ifndef MINGW32
#define qual_timestamp int64_t
#else
#define qual_timestamp long long
#endif
/* The magic "Never expire" time */
#define NEVER_EXPIRE 0

/* Structure that holds the information about either a ipv4 or ipv6 
 * connection */
typedef struct {
   unsigned char type; /* Type: 4 is ipv4; 6 is ipv6 */
   void *d; /* Data */
   int addrlen;
   } conn;

/* Structure that holds an IPV4 IP and netmask */
typedef struct {
    uint32 ip;
    uint32 mask;
    } ipv4pair;

/* Structure which is a bidirectional linked list which lists which RRs to axe
   next when the cache runs low on free spots */
typedef struct fila { /* Fila: Spanish for "line" */
    struct fila *siguiente; /* Spanish for "next" */
    struct fila *previous;
    unsigned char datatype; /* 0:rr 1:closer */
    void *record; /* This points to the record that this particular element
                     uses */
    js_string *hash_point; /* This points to the query which generates
                              the record in question */
    char nukable_hp; /* Whether the hash point string shold be destroyed
			when we remove this fila element. 1: Yes, nuke
			the hash_point string; 0: No, keep the hash
			point string */
    } fila;

/* DNS server that is closer to the answer for a given request */
typedef struct closer {
    unsigned int num_elements; /* Number of elements in the linked list */
    qual_timestamp ttd; /* Time for this record to die */
    int datatype; /* This is the RR type of the data (RR_A [in which
                     case, the data is a pointer to a uint32] or RR_NS [which
                     makes the data point to a js_string object]) */
    void *data;
    fila *zap; /* So that we can determine in which order to zap RRs */
    struct closer *masked; /* If another record with a ttd after the
                              ttd for this record exists, we want to
                              access that data when this record expires */
    struct closer *next; } closer;

/* Structure which contains the data for a DNS record pointed to from 
   the hash */
typedef struct rr {
    qual_timestamp expire; /* When this RR expires (0=authoritative/never) */
    uint32 ttl; /* The TTL for the record in question */
    uint32 authoritative; /* Are we authoritative for this zone */
    struct rr *next; /* Either the first NS for this zone _or_ the next copy
                        of the same record for the same data type */
    struct rr *ip; /* If this is a PTR, MX, or NS record, pointer to the
                      ip the rr domain name points to (if applicable) */
    js_string *ptr; /* If this is a PTR request pointing to a CNAME,
                       we want to give them the PTR record along
		       with the CNAME record. */
    uint16 rr_type; /* Type of resource record this entry is */
    js_string *query; /* Pointer to the query one asks to get this answer */
    js_string *data; /* The actual raw binary data for this RR */
    fila *zap; /* Pointer to a structure used for deleting elements from
                  the cache when the cache starts to fill up */
    char seen; /* This is used by udpsuccess() to insure that a given
                  element in the hash is only visited once */
    perm_t perms; /* What IPs can view this element; making this zero
		     means that all IPs can view the element in question */
    struct rr_list *list; /* rr_list of all records this CNAME refers to */
    char rcode; /* This is used to store the rcode for a given DNS answer */
    } rr;

/* Structure for a linked list used in the ANY (and CNAME) rr type */
typedef struct rr_list {
    uint16 rr_type;
    rr *data;
    struct rr_list *next;
    } rr_list;

/* Structure which contains the header as described in Section 4.1.1 of
   RFC1035 */
typedef struct {
    uint16 id; /* 16-bit unsigned ID of Query */
    int qr; /* Boolean query-type (query or answer) */
    int opcode; /* 4-bit opcode flag */
    int aa; /* boolean Authoritative Answer */ 
    int tc; /* boolean truncation flag */
    int rd; /* boolean "recursion desired" flag */
    int ra; /* boolean "recursion available" flag */
    int z; /* 3-bit reserved "z" flags.  Keep 0 */
    int rcode; /* 4-bit rcode flag */
    uint16 qdcount; /* 16-bit unsigned # of questions */
    uint16 ancount; /* 16-bit unsigned # of answers */
    uint16 nscount; /* 16-bit unsigned # of NS answers */
    uint16 arcount; /* 16-bit unsigned # of additional records */
    } q_header;

/* DNS Question as described in Section 4.1.2 of RFC1035 */
typedef struct {
    js_string *qname; /* Special RFC1035 format of domain name */
    uint16 qtype; /* 16-bit query type */
    uint16 qclass; /* 16-bit query class */
    } q_question;

/* RR format as described in section 4.1.3 of RFC1035 */
typedef struct {
    js_string *name; /* Special RFC1035 format of domain name */
    uint16 type; /* 16-bit record type */
    uint16 class; /* 16-bit record class */
    uint32 ttl; /* 32-bit ttl */
    uint16 rdlength; /* 16-bit length of the RDATA field */
    js_string *rdata; /* variable length resource data */
    } q_rr;

/* This is, as of June 23 2006, a list of all DNS RRs over at 
   http://www.iana.org/assignments/dns-parameters */
/* Some query types and their RFC1035 section 3.2.2 values */
/* A record: RFC1035 section 3.4.1 */
#define RR_A 1
/* NS record: RFC1035 section 3.3.11 */
#define RR_NS 2
/* Obsolete; RFC1035 */
#define RR_MD 3
/* Obsolete; RFC1035 */
#define RR_MF 4
/* CNAME: RFC1035 section 3.3.1 */
#define RR_CNAME 5
/* SOA: RFC1035 section 3.3.13 */
#define RR_SOA 6
/* EXPERIMENTAL RFC1035 RRs */
#define RR_MB 7
#define RR_MG 8
#define RR_MR 9
#define RR_NULL 10
/* Non-experimental RFC1035 RR */
#define RR_WKS 11
/* PTR: RFC1035 section 3.3.12 */
#define RR_PTR 12
/* Two more RFC1035 RRs */
#define RR_HINFO 13
#define RR_MINFO 14
/* MX: RFC1035 section 3.3.9 */
#define RR_MX 15
/* TXT: RFC1035 section 3.3.14 */
#define RR_TXT 16
/* RFC1183 RRs */
#define RR_RP 17
#define RR_AFSDB 18
#define RR_X25 19
#define RR_ISDN 20
#define RR_RT 21
/* RFC1706 RRs */
#define RR_NSAP 22
#define RR_NSAP_PTR 23
/* RFC2535, RFC3755, and RFC4034 RRs */
#define RR_SIG 24
#define RR_KEY 25
/* RFC2163 RR */
#define RR_PX 26
/* RFC1712 RR */
#define RR_GPOS 27
/* AAAA: ipv6 addresses (Not in an RFC) */
#define RR_AAAA 28
/* RFC1876 */
#define RR_LOC 29 
/* Obsolete RFC2535 and RFC3755 RR */
#define RR_NXT 30
/* "Endpoint" (Not in an RFC) */
#define RR_EID 31
/* "Nimrod" (Not in an RFC) */
#define RR_NIMLOC 32
/* SRV: "service" records (RFC2782) */
#define RR_SRV 33
/* "ATM address" (Not in an RFC) */
#define RR_ATMA 34
/* RFC2168,RFC2915 */
#define RR_NAPTR 35
/* RFC2230 */
#define RR_KX 36
/* RFC2538 */
#define RR_CENT 37
/* DON'T USE THIS A6 RR; harmful RFC2874 */
#define RR_A6 38
/* Again, harmful for same reason A6 is harmful; RFC2672 */
#define RR_DNAME 39
/* Kitchen Sink RR (Not in an RFC; looks to be a joke but BIND supports it) */
#define RR_SINK 40
/* RFC2671 */
#define RR_OPT 41 
/* RFC3123 */
#define RR_APL 42
/* RFC3658 */
#define RR_DS 43
/* RFC4255 */
#define RR_SSHFP 44
/* RFC4025 */
#define RR_IPSECKEY 45
/* 3 RFC3755 RRs */
#define RR_RRSIG 46
#define RR_NSEC 47
#define RR_DNSKEY 48
/* 49-98 are unassigned as of 2006/06/23 */
/* SPF: sender policy framework (stops forged email) record */
#define RR_SPF 99
/* Four RRs not in an RFC but are IANA-reserved */
#define RR_UINFO 100
#define RR_UID 101
#define RR_GID 102
#define RR_UNSPEC 103
/* 104-248 are unassigned as of 2006/06/23 */
/* RFC2930 */
#define RR_TKEY 249
/* RFC2845 */
#define RR_TSIG 250
/* RFC251 (treated as AXFR by zoneserver) */
#define RR_IXFR 251
/* AXFR: Special query that requests a zone transfer */
#define RR_AXFR 252
/* RFC1035; not officially obsolete but for all practical purposes
   obsolete */
#define RR_MAILB 253
/* MAILA is officially obsolete */
#define RR_MAILA 254
/* ANY: Special query for all of the records for a given hostname */
#define RR_ANY 255
/* This is not assigned by the IANA, but BIND uses this RR number */
#define RR_ZXFR 256
/* "DNSSEC Trust Authorities"; Not in an RFC */
#define RR_TA 32768
/* RFC4431 */
#define RR_DLV 32769
/* Some "magic" RR types used by askmara */
/* RR_MAGIC_SPACE: Make the character representing the RR a space */
#define RR_MAGIC_SPACE -300
/* RR_MAGIC_EMAIL: Make the character representing the RR a space, and
 * make the first "dot" an at */
#define RR_MAGIC_EMAIL -301

/* The following formats use a single domain name as the data: 
   NS CNAME PTR (MB MD MF MG) 
*/
#define rr_ns *js_string
#define rr_cname *js_string
#define rr_ptr *js_string

/* The A record is a single unsigned 32-bit integer */
#define rr_a uint32

/* The other supported types we make structures of */

/* SOA: RFC1035 3.3.13 */
typedef struct {
    js_string *mname; /* The name server with authoritative data */
    js_string *rname; /* Domain-name style data: email address */ 
    uint32 serial; /* 32-bit serial */
    int32 refresh; /* How often slave servers look at the serial to
                    see if it should be refreshed */
    int32 retry; /* How often slave servers should look at the serial when
                  the server is down */
    int32 expire; /* How long before the slave servers "give up" on looking
                   at data from the master server when the master server 
		   dies */
    uint32 minimum; /* Default TTL for all RRs in the zone */
    } rr_soa;

/* MX: RFC1035 section 3.3.9 */
typedef struct {
    int16 preference; /* Lower preference MXs are tried before higher
                         preference MXs */
    js_string *exchange; /* Domain-name style data, the actual mail
                            exchanger */
    } rr_mx;

/* The TXT record is a single RFC1035-style character-string */
#define rr_txt *js_string;

/* The various error codes we place in the RCODE section of the header */
#define FORMAT_ERROR 1
#define SERVER_FAIL 2
#define NXDOMAIN_RCODE 3
#define NOT_IMPLEMENTED 4
#define REFUSED 5

/* The longest RRs which we allow to exist in csv1 zone files.
   Warning: If you make this longer, then there is a significant
   risk that the record will be longer than the 512 bytes allowed 
   in a DNS packet.  MaraDNS does not current support DNS over TCP.
*/

#define MAX_RECORD_LENGTH 425

#endif /* MARADNSH_DEFINED */
