From 451a8eb6a969eae7e5f7f0d1b565ea96c6b160f1 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Sun, 25 Feb 2007 15:41:49 +0000 Subject: [PATCH] Allow specification of DNS vhost and server in ircd.conf. Change the default DNS vhost from the global vhost to unspecified. git-svn-id: file:///home/klmitch/undernet-ircu/undernet-ircu-svn/ircu2/branches/u2_10_12_branch@1764 c9e4aea6-c8fd-4c43-8297-357d70d61c8c --- ChangeLog | 32 ++++++++++++++++++++++++++++++++ doc/example.conf | 13 +++++++++++++ include/res.h | 2 ++ include/s_bsd.h | 2 ++ ircd/ircd_lexer.l | 1 + ircd/ircd_parser.y | 35 ++++++++++++++++++++++++++++++++++- ircd/ircd_res.c | 37 +++++++++++++++++++++++++++++++++---- ircd/ircd_reslib.c | 12 +++++------- ircd/s_conf.c | 1 + 9 files changed, 123 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 231e4ae..a43753f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,35 @@ +2007-02-25 Michael Poole + + * doc/example.conf: Document new options for General block. + + * include/res.h (clear_nameservers): Declare new function. + (add_nameserver): Declare previously static function. + + * include/s_bsd.h (VirtualHost_dns_v4): Declare. + (VirtualHost_dns_v6): Likewise. + + * ircd/ircd_lexer.l (DNS): Recognize new token. + + * ircd/ircd_parser.y (DNS): Declare new token. + (generalitem): Allow new items for dns vhost(s) and dns servers. + (generaldnsvhost): New production. + (generaldnsserver): New production. + + * ircd/ircd_res.c (VirtualHost_dns_v4): New variable. + (VirtualHost_dns_v6): Likewise. + (clear_nameservers): New function. + (restart_resolver): Scan specified servers so we only try to open + DNS client sockets that we need. + + * ircd/ircd_reslib.c (irc_nscount): Remove redundant initializer. + (irc_res_init): Only read the resolver config file if there are no + nameservers provided. + (add_nameserver): Make non-static. Remove off-by-one check + against IRCD_MAXNS. + + * ircd/s_conf.c (read_configuration_file): Clear nameserver list + before reading the config file. + 2007-01-27 Jeannot Langlois * doc/example.conf (Features): Illustrate URLREG feature. diff --git a/doc/example.conf b/doc/example.conf index a5d57bc..5e20dcb 100644 --- a/doc/example.conf +++ b/doc/example.conf @@ -56,6 +56,10 @@ # vhost = "ipv6vhost"; # description = "description"; # numeric = numericnumber; +# dns vhost = "ipv4vhost"; +# dns vhost = "ipv6vhost"; +# dns server = "ipaddress"; +# dns server = "ipaddress2"; # }; # # If present, must contain a valid address in dotted @@ -71,6 +75,15 @@ # # Note that has to be unique on the network your server # is running on, must be between 0 and 4095, and is not updated on a rehash. +# +# The two DNS lines allow you to specify the local IP address to use +# for DNS lookups ("dns vhost") and one or more DNS server addresses +# to use. If the vhost is ambiguous for some reason, you may list +# IPV4 and/or IPV6 between the equals sign and the address string. +# The default DNS vhost is to let the operating system assign the +# address, and the default DNS servers are read from /etc/resolv.conf. +# In most cases, you do not need to specify either the dns vhost or +# the dns server. General { name = "London.UK.Eu.UnderNet.org"; description = "University of London, England"; diff --git a/include/res.h b/include/res.h index 2bf44c3..582e513 100644 --- a/include/res.h +++ b/include/res.h @@ -109,6 +109,8 @@ typedef struct } HEADER; extern void restart_resolver(void); +extern void clear_nameservers(void); +extern void add_nameserver(const char *ipaddr); extern void add_local_domain(char *hname, size_t size); extern size_t cres_mem(struct Client* cptr); extern void delete_resolver_queries(const void *vptr); diff --git a/include/s_bsd.h b/include/s_bsd.h index 4977f30..8b2231d 100644 --- a/include/s_bsd.h +++ b/include/s_bsd.h @@ -53,6 +53,8 @@ extern int HighestFd; extern struct Client* LocalClientArray[MAXCONNECTIONS]; extern struct irc_sockaddr VirtualHost_v4; extern struct irc_sockaddr VirtualHost_v6; +extern struct irc_sockaddr VirtualHost_dns_v4; +extern struct irc_sockaddr VirtualHost_dns_v6; /* * Proto types diff --git a/ircd/ircd_lexer.l b/ircd/ircd_lexer.l index 231c64b..d44f106 100644 --- a/ircd/ircd_lexer.l +++ b/ircd/ircd_lexer.l @@ -103,6 +103,7 @@ static struct lexer_token { TOKEN(FAST), TOKEN(AUTOCONNECT), TOKEN(PROGRAM), + TOKEN(DNS), #undef TOKEN { "administrator", ADMIN }, { "apass_opmode", TPRIV_APASS_OPMODE }, diff --git a/ircd/ircd_parser.y b/ircd/ircd_parser.y index 2c0dddc..29b14ef 100644 --- a/ircd/ircd_parser.y +++ b/ircd/ircd_parser.y @@ -163,6 +163,7 @@ static void parse_error(char *pattern,...) { %token AUTOCONNECT %token PROGRAM %token TOK_IPV4 TOK_IPV6 +%token DNS /* and now a lot of privileges... */ %token TPRIV_CHAN_LIMIT TPRIV_MODE_LCHAN TPRIV_DEOP_LCHAN TPRIV_WALK_LCHAN %token TPRIV_LOCAL_KILL TPRIV_REHASH TPRIV_RESTART TPRIV_DIE @@ -283,7 +284,9 @@ generalblock: GENERAL parse_error("Your General block must contain a numeric (between 1 and 4095)."); }; generalitems: generalitem generalitems | generalitem; -generalitem: generalnumeric | generalname | generalvhost | generaldesc; +generalitem: generalnumeric | generalname | generalvhost | generaldesc + | generaldnsvhost | generaldnsserver; + generalnumeric: NUMERIC '=' NUMBER ';' { if (localConf.numeric == 0) @@ -329,6 +332,36 @@ generalvhost: VHOST '=' QSTRING ';' MyFree(vhost); }; +generaldnsvhost: DNS VHOST '=' address_family QSTRING ';' +{ + struct irc_in_addr addr; + int families = $4; + char *vhost = $5; + + if (!strcmp(vhost, "*")) { + /* Let the operating system assign the default. */ + } else if (!ircd_aton(&addr, vhost)) + parse_error("Invalid DNS virtual host '%s'.", vhost); + else + { + if ((families & USE_IPV4) + || (!families && irc_in_addr_is_ipv4(&addr))) + memcpy(&VirtualHost_dns_v4.addr, &addr, sizeof(addr)); + if ((families & USE_IPV6) + || (!families && !irc_in_addr_is_ipv4(&addr))) + memcpy(&VirtualHost_dns_v6.addr, &addr, sizeof(addr)); + } + MyFree(vhost); +}; + +generaldnsserver: DNS SERVER '=' QSTRING ';' +{ + char *server = $4; + + add_nameserver(server); + MyFree(server); +}; + adminblock: ADMIN { MyFree(localConf.location1); diff --git a/ircd/ircd_res.c b/ircd/ircd_res.c index b7464cd..88b0efa 100644 --- a/ircd/ircd_res.c +++ b/ircd/ircd_res.c @@ -56,6 +56,10 @@ static struct Socket res_socket_v4; static struct Socket res_socket_v6; /** Next DNS lookup timeout. */ static struct Timer res_timeout; +/** Local address for IPv4 DNS lookups. */ +struct irc_sockaddr VirtualHost_dns_v4; +/** Local address for IPv6 DNS lookups. */ +struct irc_sockaddr VirtualHost_dns_v6; /** Check for whether the resolver has been initialized yet. */ #define resolver_started() (request_list.next != NULL) @@ -142,6 +146,16 @@ extern struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS]; extern int irc_nscount; extern char irc_domain[HOSTLEN]; +/** Prepare the resolver library to (optionally) accept a list of + * DNS servers through add_dns_server(). + */ +void clear_nameservers(void) +{ + irc_nscount = 0; + memset(&VirtualHost_dns_v4, 0, sizeof(VirtualHost_dns_v4)); + memset(&VirtualHost_dns_v6, 0, sizeof(VirtualHost_dns_v6)); +} + /** Check whether \a inp is a nameserver we use. * @param[in] inp Nameserver address. * @return Non-zero if we trust \a inp; zero if not. @@ -166,23 +180,38 @@ res_ourserver(const struct irc_sockaddr *inp) void restart_resolver(void) { + int need_v4; + int need_v6; + int ns; + irc_res_init(); if (!request_list.next) request_list.next = request_list.prev = &request_list; - if (!s_active(&res_socket_v4)) + /* Check which address family (or families) our nameservers use. */ + for (need_v4 = need_v6 = ns = 0; ns < irc_nscount; ns++) + { + if (irc_in_addr_is_ipv4(&irc_nsaddr_list[ns].addr)) + need_v4 = 1; + else + need_v6 = 1; + } + + /* If we need an IPv4 socket, and don't have one, open it. */ + if (need_v4 && !s_active(&res_socket_v4)) { - int fd = os_socket(&VirtualHost_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET); + int fd = os_socket(&VirtualHost_dns_v4, SOCK_DGRAM, "Resolver UDPv4 socket", AF_INET); if (fd >= 0) socket_add(&res_socket_v4, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); } #ifdef AF_INET6 - if (!s_active(&res_socket_v6)) + /* If we need an IPv6 socket, and don't have one, open it. */ + if (need_v6 && !s_active(&res_socket_v6)) { - int fd = os_socket(&VirtualHost_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6); + int fd = os_socket(&VirtualHost_dns_v6, SOCK_DGRAM, "Resolver UDPv6 socket", AF_INET6); if (fd >= 0) socket_add(&res_socket_v6, res_readreply, NULL, SS_DATAGRAM, SOCK_EVENT_READABLE, fd); diff --git a/ircd/ircd_reslib.c b/ircd/ircd_reslib.c index 4b934e9..b637273 100644 --- a/ircd/ircd_reslib.c +++ b/ircd/ircd_reslib.c @@ -105,7 +105,7 @@ /** Array of nameserver addresses. */ struct irc_sockaddr irc_nsaddr_list[IRCD_MAXNS]; /** Number of nameservers in #irc_nsaddr_list. */ -int irc_nscount = 0; +int irc_nscount; /** Local domain to use as a search suffix. */ char irc_domain[HOSTLEN + 1]; @@ -130,7 +130,6 @@ static const char digitvalue[256] = { }; static int parse_resvconf(void); -static void add_nameserver(char *arg); /** Array of decimal digits, indexed by value. */ static const char digits[] = "0123456789"; @@ -152,8 +151,7 @@ static int mklower(int ch); int irc_res_init(void) { - irc_nscount = 0; - return(parse_resvconf()); + return (irc_nscount == 0) ? parse_resvconf() : 0; } /** Read resolver configuration file for domain and nameserver lines. @@ -223,13 +221,13 @@ parse_resvconf(void) /** Add a resolver to #irc_nsaddr_list. * @param[in] arg Dotted quad or IPv6 text form of nameserver address. */ -static void -add_nameserver(char *arg) +void +add_nameserver(const char *arg) { struct irc_sockaddr res; /* Done max number of nameservers? */ - if ((irc_nscount + 1) >= IRCD_MAXNS) + if (irc_nscount >= IRCD_MAXNS) return; /* Failure converting from numeric string? */ diff --git a/ircd/s_conf.c b/ircd/s_conf.c index f4dde53..9b37dc2 100644 --- a/ircd/s_conf.c +++ b/ircd/s_conf.c @@ -826,6 +826,7 @@ int read_configuration_file(void) { conf_error = 0; feature_unmark(); /* unmark all features for resetting later */ + clear_nameservers(); /* clear previous list of DNS servers */ /* Now just open an fd. The buffering isn't really needed... */ init_lexer(); yyparse(); -- 2.20.1