├── .github └── workflows │ └── build.yml ├── AUTHORS ├── COPYING ├── ChangeLog ├── LICENSE ├── Makefile.am ├── NEWS ├── README ├── README.md ├── bootstrap ├── configure.ac ├── daemon.c ├── dnsproxy.8.in ├── dnsproxy.c ├── dnsproxy.conf ├── dnsproxy.h ├── hash.c ├── internal.c ├── log.c ├── parse.c └── stats.c /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build-check 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: ubuntu-latest 9 | 10 | steps: 11 | - uses: actions/checkout@v2 12 | - name: install_dependencies 13 | run: sudo apt update && sudo apt install libevent-dev 14 | - name: build_dist_distclean 15 | run: | 16 | ./bootstrap 17 | ./configure 18 | make 19 | make dist 20 | ls dnsproxy-[0-9]*.tar.gz 21 | make distclean 22 | - name: build_install_run 23 | run: | 24 | ./bootstrap 25 | ./configure 26 | make 27 | sudo make install 28 | dnsproxy -V 29 | dnsproxy -h 2>&1 | egrep -iC10 usage 30 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awaw/dnsproxy/cb47c84bbb6fb5a69c41122178dbe964e90a2e25/AUTHORS -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | LICENSE -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awaw/dnsproxy/cb47c84bbb6fb5a69c41122178dbe964e90a2e25/ChangeLog -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2003,2004,2005,2010,2016,2017 Armin Wolfermann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | sbin_PROGRAMS = dnsproxy 2 | dnsproxy_SOURCES = dnsproxy.c dnsproxy.h \ 3 | daemon.c hash.c internal.c log.c parse.c stats.c 4 | 5 | man_MANS = dnsproxy.8 6 | 7 | distclean-local: 8 | rm -rf autom4te.cache dnsproxy-[0-9]* 9 | rm -f aclocal.m4 compile config.* configure depcomp install-sh \ 10 | INSTALL Makefile.in missing 11 | -------------------------------------------------------------------------------- /NEWS: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/awaw/dnsproxy/cb47c84bbb6fb5a69c41122178dbe964e90a2e25/NEWS -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | README.md -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | #### DESCRIPTION 2 | 3 | The dnsproxy daemon is a proxy for DNS queries. It forwards these queries 4 | to two previously configured nameservers: one for authoritative queries 5 | and another for recursive queries. The received answers are sent back to 6 | the client unchanged. No local caching is done and only UDP queries are 7 | supported. 8 | 9 | Primary motivation for this project was the need to replace Bind servers 10 | with djbdns in an ISP environment. These servers got recursive queries 11 | from customers and authoritative queries from outside at the same IP 12 | address. Now it was possible to run dnscache and tinydns on the same 13 | machine with queries dispatched by dnsproxy. 14 | 15 | Other scenarios are firewalls where you want to proxy queries to the real 16 | servers in your DMZ. Or internal nameservers behind firewalls, or... 17 | 18 | Some features: 19 | - Secure. Runs chrooted and without root privileges. 20 | - Fast. Able to process hundreds of queries per second. 21 | - Easy to setup. Simple configuration file. 22 | 23 | #### INSTALLATION 24 | 25 | If you run any current UNIX-like operating system, only the following 26 | steps should be necessary: 27 | ``` 28 | ./configure 29 | make 30 | make install 31 | ``` 32 | Unlike earlier releases this release does not include the libevent 33 | library. It should now also be available from your operating systems 34 | ports/packages/rpm/deb repository or as always from the source at 35 | http://libevent.org/. If it is not found by the configure script 36 | you may specify the directory prefix of your libevent installation 37 | with: 38 | ``` 39 | ./configure --with-libevent=/usr/local 40 | ``` 41 | 42 | #### CONFIGURATION 43 | 44 | At startup dnsproxy reads a configuration file specified via the -c 45 | option or at the default location of /etc/dnsproxy.conf. The syntax of 46 | this configuration file is of the form "keyword value" and looks like: 47 | ``` 48 | authoritative 127.0.0.1 # Authoritative server. Required. 49 | authoritative-port 53001 # It's port. Defaults to 53. 50 | authoritative-timeout 10 # Seconds to wait for answers. 51 | 52 | recursive 127.0.0.1 # Recursive server. Required. 53 | recursive-port 53002 # It's port. Defaults to 53. 54 | recursive-timeout 90 # Seconds to wait for answers. 55 | 56 | listen 192.168.168.1 # Dnsproxy's listen address. 57 | port 53 # Dnsproxy's port address. 58 | 59 | chroot /var/empty # Directory to chroot dnsproxy. 60 | user nobody # Unprivileged user to run as. 61 | 62 | internal 192.168.168.0/24 # Only internal IP addresses are 63 | internal 127.0.0.1 # allowed to do recursive queries. 64 | 65 | statistics 3600 # Print statistics every hour. 66 | ``` 67 | 68 | #### COMPATIBILITY 69 | 70 | This package should build and run on OpenBSD, FreeBSD, Solaris, Linux. 71 | Other POSIX environments should work also. Please drop me a mail if 72 | you run dnsproxy on an unlisted system. 73 | 74 | #### LICENSE 75 | 76 | This software is released under an OSI approved MIT-style license. 77 | 78 | -------------------------------------------------------------------------------- /bootstrap: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export AUTOCONF_VERSION=2.69 3 | export AUTOMAKE_VERSION=1.15 4 | autoreconf -fi && echo "Bootstrapped successfully. Now run configure." 5 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT(dnsproxy, 1.17) 2 | AC_PREREQ(2.60) 3 | 4 | AC_CONFIG_HEADERS(config.h) 5 | AM_INIT_AUTOMAKE 6 | 7 | dnl ------------------------------------------------------------------ 8 | dnl Check for programs 9 | dnl ------------------------------------------------------------------ 10 | 11 | AC_PROG_CC 12 | AC_PROG_CPP 13 | AC_PROG_INSTALL 14 | AC_PROG_MAKE_SET 15 | AC_CACHE_SAVE 16 | 17 | dnl ------------------------------------------------------------------ 18 | dnl Check for headers 19 | dnl ------------------------------------------------------------------ 20 | 21 | AC_USE_SYSTEM_EXTENSIONS 22 | AC_C_CONST 23 | AC_HEADER_STDC 24 | AC_HEADER_TIME 25 | AC_CHECK_HEADERS(sys/types.h sys/socket.h sys/time.h) 26 | AC_CHECK_HEADERS(netinet/in.h arpa/inet.h) 27 | AC_CHECK_HEADERS(errno.h syslog.h) 28 | AC_TYPE_SIGNAL 29 | AC_CACHE_SAVE 30 | 31 | dnl ------------------------------------------------------------------ 32 | dnl Check for functions 33 | dnl ------------------------------------------------------------------ 34 | 35 | AC_CHECK_FUNCS(strchr memcpy) 36 | AC_CHECK_FUNCS(setregid setresgid setresuid setreuid) 37 | AC_CACHE_SAVE 38 | 39 | dnl ------------------------------------------------------------------ 40 | dnl Check for additional libraries 41 | dnl ------------------------------------------------------------------ 42 | 43 | AC_SEARCH_LIBS([gethostbyname], [nsl]) 44 | AC_SEARCH_LIBS([socket], [socket], [], [ 45 | AC_CHECK_LIB([socket], [socket], [LIBS="-lsocket -lnsl $LIBS"], [], 46 | [-lnsl]) 47 | ]) 48 | AC_CACHE_SAVE 49 | 50 | dnl ------------------------------------------------------------------ 51 | dnl Enable extended warnings while developing 52 | dnl ------------------------------------------------------------------ 53 | 54 | AC_ARG_ENABLE(warnings, [ 55 | AC_HELP_STRING([--enable-warnings], 56 | [enable all sorts of warnings for debugging])], 57 | [ 58 | CFLAGS="${CFLAGS} -Wall -Werror -Wcast-qual -Wmissing-declarations \ 59 | -W -Wmissing-prototypes -Wnested-externs -Wshadow \ 60 | -Wwrite-strings -Wno-unused -Wno-sign-compare" 61 | ]) 62 | AC_SUBST(CFLAGS) 63 | 64 | dnl ------------------------------------------------------------------ 65 | dnl Maximum EDNS packet size 66 | dnl ------------------------------------------------------------------ 67 | 68 | AC_ARG_ENABLE([edns], [ 69 | AC_HELP_STRING([--enable-edns=N], 70 | [maximum EDNS packet size (default is 4096)])], 71 | [], [enable_edns=4096]) 72 | AS_IF([test $enable_edns = no], [enable_edns=4096]) 73 | AC_DEFINE_UNQUOTED([MAXEDNS],[$enable_edns],[Maximum EDNS packet size]) 74 | 75 | dnl ------------------------------------------------------------------ 76 | dnl Check for libevent library 77 | dnl ------------------------------------------------------------------ 78 | 79 | lefound="no" 80 | LIBS="$LIBS -levent" 81 | AC_MSG_CHECKING(for libevent) 82 | AC_ARG_WITH(libevent, 83 | AC_HELP_STRING( 84 | [--with-libevent=PATH], 85 | [directory prefix where libevent is found] 86 | ), 87 | [ 88 | if test -f $withval/include/event.h; then 89 | CFLAGS="${CFLAGS} -I$withval/include" 90 | elif test -f $withval/event.h; then 91 | CFLAGS="${CFLAGS} -I$withval" 92 | else 93 | AC_ERROR([event.h not found]) 94 | fi 95 | if test -f $withval/lib; then 96 | LDFLAGS="${LDFLAGS} -L$withval/lib" 97 | else 98 | LDFLAGS="${LDFLAGS} -L$withval" 99 | fi 100 | AC_MSG_RESULT([using $withval]) 101 | lefound="yes" 102 | ], 103 | [ 104 | saved_CFLAGS=$CFLAGS 105 | saved_LDFLAGS=$LDFLAGS 106 | for testdir in "" $prefix /usr/local /opt/csw; do 107 | if test -z "$testdir"; then 108 | CFLAGS="$saved_CFLAGS" 109 | LDFLAGS="$saved_LDFLAGS" 110 | else 111 | CFLAGS="$saved_CFLAGS -I$testdir/include" 112 | LDFLAGS="$saved_LDFLAGS -L$testdir/lib" 113 | fi 114 | 115 | AC_TRY_LINK([#include 116 | #include 117 | #include ], 118 | [ event_init(); ], 119 | [ lefound="$testdir" ], 120 | [ lefound="no" ]) 121 | 122 | if test "$lefound" != "no"; then 123 | if test -z "$testdir"; then 124 | AC_MSG_RESULT([found]) 125 | else 126 | AC_MSG_RESULT([found in $lefound]) 127 | fi 128 | break 129 | fi 130 | done 131 | ] 132 | ) 133 | 134 | if test "$lefound" = "no"; then 135 | AC_MSG_ERROR([ 136 | This software requires the libevent library 137 | available at http://libevent.org/ 138 | 139 | You may specify it's directory prefix with 140 | ./configure --with-libevent=/prefix/of/libevent 141 | ]) 142 | fi 143 | 144 | dnl ------------------------------------------------------------------ 145 | dnl Check for available nroff and manpage macro package 146 | dnl ------------------------------------------------------------------ 147 | 148 | AC_PATH_PROGS([NROFF], [nroff awf], [/bin/false], [$PATH:/usr/ucb]) 149 | if ${NROFF} -mdoc dnsproxy.8 >/dev/null 2>&1; then 150 | MAN=mdoc 151 | else 152 | MAN=man 153 | fi 154 | AC_SUBST(MAN) 155 | 156 | dnl ------------------------------------------------------------------ 157 | dnl Generate Makefile by default. Others only if their .in file 158 | dnl exists in the current directory, which happens in my workdir 159 | dnl but not for distributed tarballs. 160 | dnl ------------------------------------------------------------------ 161 | 162 | AC_CONFIG_FILES(Makefile) 163 | if test -r "dnsproxy.8.in"; then 164 | AC_CONFIG_FILES(dnsproxy.8) 165 | fi 166 | 167 | AC_OUTPUT() 168 | 169 | AC_MSG_RESULT() 170 | AC_MSG_RESULT([Configured successfully. Now run make.]) 171 | AC_MSG_RESULT() 172 | -------------------------------------------------------------------------------- /daemon.c: -------------------------------------------------------------------------------- 1 | /*- 2 | * Copyright (c) 1990, 1993 3 | * The Regents of the University of California. All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 3. Neither the name of the University nor the names of its contributors 14 | * may be used to endorse or promote products derived from this software 15 | * without specific prior written permission. 16 | * 17 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 | * SUCH DAMAGE. 28 | * 29 | * From: $OpenBSD: daemon.c,v 1.5 2003/07/15 17:32:41 deraadt Exp $ 30 | */ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include "dnsproxy.h" 37 | 38 | int 39 | daemon(int nochdir, int noclose) 40 | { 41 | int fd; 42 | 43 | switch (fork()) { 44 | case -1: 45 | return (-1); 46 | case 0: 47 | break; 48 | default: 49 | _exit(0); 50 | } 51 | 52 | if (setsid() == -1) 53 | return (-1); 54 | 55 | if (!nochdir) 56 | if (chdir("/")) 57 | return (-1); 58 | 59 | if (!noclose && (fd = open("/dev/null", O_RDWR, 0)) != -1) { 60 | (void)dup2(fd, STDIN_FILENO); 61 | (void)dup2(fd, STDOUT_FILENO); 62 | (void)dup2(fd, STDERR_FILENO); 63 | if (fd > 2) 64 | (void)close (fd); 65 | } 66 | return (0); 67 | } 68 | -------------------------------------------------------------------------------- /dnsproxy.8.in: -------------------------------------------------------------------------------- 1 | .\" 2 | .\" Copyright (c) 2003,2004 Armin Wolfermann 3 | .\" 4 | .\" Permission is hereby granted, free of charge, to any person obtaining a 5 | .\" copy of this software and associated documentation files (the "Software"), 6 | .\" to deal in the Software without restriction, including without limitation 7 | .\" the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | .\" and/or sell copies of the Software, and to permit persons to whom the 9 | .\" Software is furnished to do so, subject to the following conditions: 10 | .\" 11 | .\" The above copyright notice and this permission notice shall be included in 12 | .\" all copies or substantial portions of the Software. 13 | .\" 14 | .\" THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | .\" IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | .\" FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | .\" THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | .\" LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | .\" FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | .\" DEALINGS IN THE SOFTWARE. 21 | .\" 22 | .Dd November 29, 2003 23 | .Dt DNSPROXY 8 24 | .Os LOCAL 25 | .Sh NAME 26 | .Nm dnsproxy 27 | .Nd DNS proxy 28 | .Sh SYNOPSIS 29 | .Nm dnsproxy 30 | .Op Fl dhV 31 | .Op Fl c Ar file 32 | .\" ------------------------------------------------------------------ 33 | .Sh DESCRIPTION 34 | .\" ------------------------------------------------------------------ 35 | The 36 | .Nm 37 | daemon waits for nameserver queries on a user specified 38 | address, dispatches these queries to authoritative and recursive 39 | nameservers and forwards the received answers back to the original 40 | client. 41 | .Pp 42 | The options are as follows: 43 | .Bl -tag -width Dfxfile 44 | .It Fl c Ar file 45 | Read configuration from file. 46 | .It Fl d 47 | Detach from current terminal and run as background process. 48 | .It Fl h 49 | Show usage. 50 | .It Fl V 51 | Show version. 52 | .El 53 | .Pp 54 | If a client from an internal IP address does a recursive lookup 55 | the query is forwarded to a recursive DNS server. 56 | Authoritative queries and queries coming from clients in 57 | foreign networks are forwarded to an authoritative DNS server. 58 | .Pp 59 | .\" ------------------------------------------------------------------ 60 | .Sh CONFIGURATION FILE 61 | .\" ------------------------------------------------------------------ 62 | At startup 63 | .Nm 64 | reads a configuration file specified via the -c option 65 | or at the default location of /etc/dnsproxy.conf. 66 | .Pp 67 | The following keywords are recognized: 68 | .Bl -ohang 69 | .It authoritative Ar IP 70 | Address of the authoritative nameserver [required]. 71 | .It recursive Ar IP 72 | Address of the recursive nameserver [required]. 73 | .It listen Ar IP 74 | Local address (defaults to 0.0.0.0). 75 | .It port Ar number 76 | Local port number (defaults to 53). 77 | .It chroot Ar path 78 | A path to chroot to before starting to answer queries. 79 | .It user Ar name 80 | A user to change to before starting to answer queries. 81 | .It authoritative-timeout Ar seconds 82 | Time in seconds when authoritative queries time out (defaults to 10). 83 | .It recursive-timeout Ar seconds 84 | Time in seconds when recursive queries time out (defaults to 90). 85 | .It authoritative-port Ar number 86 | Port number on authoritative nameserver (defaults to 53). 87 | .It recursive-port Ar number 88 | Port number on recursive nameserver (defaults to 53). 89 | .It statistics Ar seconds 90 | Period between output of statistics (defaults to 3600). 91 | Use 0 to disable output of statistics completely. 92 | .It internal Fa network 93 | Declare networks recognized as internal and thus eligible to do 94 | recursive queries. One network in CIDR notation per keyword. 95 | .El 96 | .Ss EXAMPLE 97 | .Bd -literal -offset indent 98 | authoritative 10.1.1.1 99 | recursive 127.0.0.1 100 | recursive-port 10053 101 | listen 192.168.1.1 102 | port 53 103 | chroot /var/empty 104 | user nobody 105 | internal 192.168.1.0/24 106 | internal 127.0.0.1 107 | .Ed 108 | .Pp 109 | .\" ------------------------------------------------------------------ 110 | .Sh STATISTICS 111 | .\" ------------------------------------------------------------------ 112 | Every hour (by default) 113 | .Nm 114 | logs the collected statistics about its usage to standard error 115 | (or syslog when running detached). Statistics look like 116 | .Bd -literal -offset indent 117 | ActiveQr AuthorQr RecursQr AllQuery Answered 118 | 0 0 0 0 0 119 | TimeoutQ DroppedQ DroppedA LateAnsw HashColl 120 | 0 0 0 0 0 121 | .Ed 122 | .Pp 123 | and have the following meaning: 124 | .Bl -ohang 125 | .It ActiveQr 126 | Number of currently active queries proxied to the servers. 127 | .It AuthorQr 128 | Accumulated number of authoritative queries. 129 | .It RecursQr 130 | Accumulated number of recursive queries. 131 | .It AllQuery 132 | Accumulated number of all queries ever received. 133 | .It Answered 134 | Accumulated number of answered queries. 135 | .It TimeoutQ 136 | Accumulated number of queries that did not receive an answer in time. 137 | .It DroppedQ 138 | Accumulated number of dropped queries (e.g. transmission errors). 139 | .It DroppedA 140 | Accumulated number of dropped answers. 141 | .It LateAnsw 142 | Accumulated number of answers received after the timeout period. 143 | .It HashColl 144 | Accumulated number of hash collisions in the query list. 145 | .El 146 | .\" 147 | .Sh SEE ALSO 148 | .Xr named 8 149 | .Sh VERSION 150 | This manual page describes 151 | .Nm 152 | version @PACKAGE_VERSION@. 153 | .Sh AUTHORS 154 | Armin Wolfermann 155 | .Pp 156 | The 157 | .Nm 158 | homepage is at http://www.wolfermann.org/dnsproxy.html. 159 | .Pp 160 | -------------------------------------------------------------------------------- /dnsproxy.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004,2005,2010,2016 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | #define GLOBALS 1 34 | #include "dnsproxy.h" 35 | 36 | #define RD(x) (*(x + 2) & 0x01) 37 | 38 | static unsigned short queryid = 0; 39 | #define QUERYID queryid++ 40 | 41 | static struct sockaddr_in authoritative_addr; 42 | static struct sockaddr_in recursive_addr; 43 | static int sock_query; 44 | static int sock_answer; 45 | static int dnsproxy_sig; 46 | 47 | extern int event_gotsig; 48 | extern int (*event_sigcb)(void); 49 | 50 | #ifdef DEBUG 51 | char *malloc_options = "AGZ"; 52 | #endif 53 | 54 | /* signal_handler -- Called by libevent if a signal arrives. 55 | */ 56 | 57 | void 58 | signal_handler(int sig, short event, void *arg) 59 | { 60 | (void)event_loopexit(NULL); 61 | fatal("exiting on signal %d", sig); 62 | } 63 | 64 | /* timeout -- Called by the event loop when a query times out. Removes the 65 | * query from the queue. 66 | */ 67 | 68 | /* ARGSUSED */ 69 | static void 70 | timeout(int fd, short event, void *arg) 71 | { 72 | hash_remove_request((struct request *)arg); 73 | free((struct request *)arg); 74 | ++removed_queries; 75 | } 76 | 77 | /* do_query -- Called by the event loop when a packet arrives at our 78 | * listening socket. Read the packet, create a new query, append it to the 79 | * queue and send it to the correct server. 80 | */ 81 | 82 | /* ARGSUSED */ 83 | static void 84 | do_query(int fd, short event, void *arg) 85 | { 86 | char buf[MAXEDNS]; 87 | int byte = 0; 88 | struct sockaddr_in fromaddr; 89 | unsigned int fromlen = sizeof(fromaddr); 90 | struct request *req; 91 | struct timeval tv; 92 | 93 | ++all_queries; 94 | 95 | /* Reschedule event */ 96 | event_add((struct event *)arg, NULL); 97 | 98 | /* read packet from socket */ 99 | if ((byte = recvfrom(fd, buf, sizeof(buf), 0, 100 | (struct sockaddr *)&fromaddr, &fromlen)) == -1) { 101 | error("recvfrom failed: %s", strerror(errno)); 102 | ++dropped_queries; 103 | return; 104 | } 105 | 106 | /* check for minimum dns packet length */ 107 | if (byte < 12) { 108 | error("query too short from %s", 109 | inet_ntoa(fromaddr.sin_addr)); 110 | ++dropped_queries; 111 | return; 112 | } 113 | 114 | /* allocate new request */ 115 | if ((req = calloc(1, sizeof(struct request))) == NULL) { 116 | error("calloc: %s", strerror(errno)); 117 | ++dropped_queries; 118 | return; 119 | } 120 | 121 | /* fill the request structure */ 122 | req->id = QUERYID; 123 | memcpy(&req->client, &fromaddr, sizeof(struct sockaddr_in)); 124 | memcpy(&req->clientid, &buf[0], 2); 125 | 126 | /* where is this query coming from? */ 127 | if (is_internal(fromaddr.sin_addr)) { 128 | req->recursion = RD(buf); 129 | DPRINTF(("Internal query RD=%d\n", req->recursion)); 130 | } else { 131 | /* no recursion for foreigners */ 132 | req->recursion = 0; 133 | DPRINTF(("External query RD=%d\n", RD(buf))); 134 | } 135 | 136 | /* insert it into the hash table */ 137 | hash_add_request(req); 138 | 139 | /* overwrite the original query id */ 140 | memcpy(&buf[0], &req->id, 2); 141 | 142 | if (req->recursion) { 143 | 144 | /* recursive queries timeout in 90s */ 145 | event_set(&req->timeout, -1, 0, timeout, req); 146 | tv.tv_sec=recursive_timeout; tv.tv_usec=0; 147 | event_add(&req->timeout, &tv); 148 | 149 | /* send it to our recursive server */ 150 | if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0, 151 | (struct sockaddr *)&recursive_addr, 152 | sizeof(struct sockaddr_in))) == -1) { 153 | error("sendto failed: %s", strerror(errno)); 154 | ++dropped_queries; 155 | return; 156 | } 157 | 158 | ++recursive_queries; 159 | 160 | } else { 161 | 162 | /* authoritative queries timeout in 10s */ 163 | event_set(&req->timeout, -1, 0, timeout, req); 164 | tv.tv_sec=authoritative_timeout; tv.tv_usec=0; 165 | event_add(&req->timeout, &tv); 166 | 167 | /* send it to our authoritative server */ 168 | if ((byte = sendto(sock_answer, buf, (unsigned int)byte, 0, 169 | (struct sockaddr *)&authoritative_addr, 170 | sizeof(struct sockaddr_in))) == -1) { 171 | error("sendto failed: %s", strerror(errno)); 172 | ++dropped_queries; 173 | return; 174 | } 175 | 176 | ++authoritative_queries; 177 | } 178 | } 179 | 180 | /* do_answer -- Process a packet coming from our authoritative or recursive 181 | * server. Find the corresponding query and send answer back to querying 182 | * host. 183 | */ 184 | 185 | /* ARGSUSED */ 186 | static void 187 | do_answer(int fd, short event, void *arg) 188 | { 189 | char buf[MAXEDNS]; 190 | int byte = 0; 191 | struct request *query = NULL; 192 | 193 | /* Reschedule event */ 194 | event_add((struct event *)arg, NULL); 195 | 196 | /* read packet from socket */ 197 | if ((byte = recvfrom(fd, buf, sizeof(buf), 0, NULL, NULL)) == -1) { 198 | error("recvfrom failed: %s", strerror(errno)); 199 | ++dropped_answers; 200 | return; 201 | } 202 | 203 | /* check for minimum dns packet length */ 204 | if (byte < 12) { 205 | error("answer too short"); 206 | ++dropped_answers; 207 | return; 208 | } 209 | 210 | /* find corresponding query */ 211 | if ((query = hash_find_request(*((unsigned short *)&buf))) == NULL) { 212 | ++late_answers; 213 | return; 214 | } 215 | event_del(&query->timeout); 216 | hash_remove_request(query); 217 | 218 | /* restore original query id */ 219 | memcpy(&buf[0], &query->clientid, 2); 220 | 221 | /* send answer back to querying host */ 222 | if (sendto(sock_query, buf, (unsigned int)byte, 0, 223 | (struct sockaddr *)&query->client, 224 | sizeof(struct sockaddr_in)) == -1) { 225 | error("sendto failed: %s", strerror(errno)); 226 | ++dropped_answers; 227 | } else 228 | ++answered_queries; 229 | 230 | free(query); 231 | } 232 | 233 | /* main -- dnsproxy main function 234 | */ 235 | 236 | int 237 | main(int argc, char *argv[]) 238 | { 239 | int ch; 240 | struct passwd *pw = NULL; 241 | struct sockaddr_in addr; 242 | struct event evq, eva; 243 | struct event evsigint, evsigterm, evsighup; 244 | const char *config = "/etc/dnsproxy.conf"; 245 | int daemonize = 0; 246 | 247 | /* Process commandline arguments */ 248 | while ((ch = getopt(argc, argv, "c:dhV")) != -1) { 249 | switch (ch) { 250 | case 'c': 251 | config = optarg; 252 | break; 253 | case 'd': 254 | daemonize = 1; 255 | break; 256 | case 'V': 257 | fprintf(stderr, PACKAGE_STRING "\n"); 258 | exit(0); 259 | /* FALLTHROUGH */ 260 | case 'h': 261 | default: 262 | fprintf(stderr, 263 | "usage: dnsproxy [-c file] [-dhV]\n" \ 264 | "\t-c file Read configuration from file\n" \ 265 | "\t-d Detach and run as a daemon\n" \ 266 | "\t-h This help text\n" \ 267 | "\t-V Show version information\n"); 268 | exit(1); 269 | } 270 | } 271 | 272 | /* Parse configuration and check required parameters */ 273 | if (!parse(config)) 274 | fatal("unable to parse configuration"); 275 | 276 | if (!authoritative || !recursive) 277 | fatal("No authoritative or recursive server defined"); 278 | 279 | if (!listenat) 280 | listenat = strdup("0.0.0.0"); 281 | 282 | /* Create and bind query socket */ 283 | if ((sock_query = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 284 | fatal("unable to create socket: %s", strerror(errno)); 285 | 286 | memset(&addr, 0, sizeof(struct sockaddr_in)); 287 | addr.sin_addr.s_addr = inet_addr(listenat); 288 | addr.sin_port = htons(port); 289 | addr.sin_family = AF_INET; 290 | 291 | if (bind(sock_query, (struct sockaddr *)&addr, sizeof(addr)) != 0) 292 | fatal("unable to bind socket: %s", strerror(errno)); 293 | 294 | /* Create answer socket */ 295 | if ((sock_answer = socket(AF_INET, SOCK_DGRAM, 0)) == -1) 296 | fatal("unable to create socket: %s", strerror(errno)); 297 | 298 | /* Fill sockaddr_in structs for both servers */ 299 | memset(&authoritative_addr, 0, sizeof(struct sockaddr_in)); 300 | authoritative_addr.sin_addr.s_addr = inet_addr(authoritative); 301 | authoritative_addr.sin_port = htons(authoritative_port); 302 | authoritative_addr.sin_family = AF_INET; 303 | 304 | memset(&recursive_addr, 0, sizeof(struct sockaddr_in)); 305 | recursive_addr.sin_addr.s_addr = inet_addr(recursive); 306 | recursive_addr.sin_port = htons(recursive_port); 307 | recursive_addr.sin_family = AF_INET; 308 | 309 | /* Daemonize if requested and switch to syslog */ 310 | if (daemonize) { 311 | if (daemon(0, 0) == -1) 312 | fatal("unable to daemonize"); 313 | log_syslog("dnsproxy"); 314 | } 315 | 316 | /* Find less privileged user */ 317 | if (user) { 318 | pw = getpwnam(user); 319 | if (!pw) 320 | fatal("unable to find user %s", user); 321 | } 322 | 323 | /* Do a chroot if requested */ 324 | if (chrootdir) { 325 | if (chroot(chrootdir) == -1) 326 | fatal("unable to chroot to %s", chrootdir); 327 | if (chdir("/") == -1) 328 | fatal("unable to chdir"); 329 | } 330 | 331 | /* Drop privileges */ 332 | if (user) { 333 | if (setgroups(1, &pw->pw_gid) < 0) 334 | fatal("setgroups: %s", strerror(errno)); 335 | #if defined(HAVE_SETRESGID) 336 | if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) < 0) 337 | fatal("setresgid: %s", strerror(errno)); 338 | #elif defined(HAVE_SETREGID) 339 | if (setregid(pw->pw_gid, pw->pw_gid) < 0) 340 | fatal("setregid: %s", strerror(errno)); 341 | #else 342 | if (setegid(pw->pw_gid) < 0) 343 | fatal("setegid: %s", strerror(errno)); 344 | if (setgid(pw->pw_gid) < 0) 345 | fatal("setgid: %s", strerror(errno)); 346 | #endif 347 | #if defined(HAVE_SETRESUID) 348 | if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) < 0) 349 | fatal("setresuid: %s", strerror(errno)); 350 | #elif defined(HAVE_SETREUID) 351 | if (setreuid(pw->pw_uid, pw->pw_uid) < 0) 352 | fatal("setreuid: %s", strerror(errno)); 353 | #else 354 | if (seteuid(pw->pw_uid) < 0) 355 | fatal("seteuid: %s", strerror(errno)); 356 | if (setuid(pw->pw_uid) < 0) 357 | fatal("setuid: %s", strerror(errno)); 358 | #endif 359 | } 360 | 361 | event_init(); 362 | 363 | /* Take care of signals */ 364 | signal_set(&evsigint, SIGINT, signal_handler, NULL); 365 | signal_set(&evsigterm, SIGTERM, signal_handler, NULL); 366 | signal_set(&evsighup, SIGHUP, signal_handler, NULL); 367 | signal_add(&evsigint, NULL); 368 | signal_add(&evsigterm, NULL); 369 | signal_add(&evsighup, NULL); 370 | 371 | /* Zero counters and start statistics timer */ 372 | statistics_start(); 373 | 374 | /* Install query and answer event handlers */ 375 | event_set(&evq, sock_query, EV_READ, do_query, &evq); 376 | event_set(&eva, sock_answer, EV_READ, do_answer, &eva); 377 | event_add(&evq, NULL); 378 | event_add(&eva, NULL); 379 | 380 | /* Start libevent main loop */ 381 | event_dispatch(); 382 | 383 | return 0; 384 | } 385 | -------------------------------------------------------------------------------- /dnsproxy.conf: -------------------------------------------------------------------------------- 1 | # 2 | # dnsproxy 1.15 configuration file example 3 | # 4 | 5 | # 6 | # Authoritative server 7 | # 8 | authoritative 127.0.0.1 9 | authoritative-port 53001 # It's port. Defaults to 53. 10 | authoritative-timeout 10 # Seconds to wait for answers. 11 | 12 | # 13 | # Recursive resolver 14 | # 15 | recursive 127.0.0.1 16 | recursive-port 53002 # It's port. Defaults to 53. 17 | recursive-timeout 90 # Seconds to wait for answers. 18 | 19 | # 20 | # Local address and port of dnsproxy 21 | # 22 | listen 192.168.168.1 23 | port 53000 24 | 25 | # 26 | # Security features 27 | # 28 | chroot /var/empty 29 | user nobody 30 | 31 | # 32 | # Internal networks (allowed to do recursive queries) 33 | # 34 | internal 192.168.168.0/24 # Our internal network 35 | internal 192.168.169.0/24 # Friendly neighbours 36 | internal 127.0.0.1 37 | 38 | -------------------------------------------------------------------------------- /dnsproxy.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004,2005,2010 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #ifndef _DNSPROXY_H_ 24 | #define _DNSPROXY_H_ 25 | 26 | /* LONGLONG */ 27 | #include 28 | 29 | #if TIME_WITH_SYS_TIME 30 | # include 31 | # include 32 | #else 33 | # if HAVE_SYS_TIME_H 34 | # include 35 | # else 36 | # include 37 | # endif 38 | #endif 39 | 40 | #include 41 | #include 42 | #if HAVE_ARPA_INET_H 43 | # include 44 | #endif 45 | #include 46 | 47 | #include 48 | 49 | #ifdef DEBUG 50 | #define DPRINTF(x) do { printf x ; } while (0) 51 | #else 52 | #define DPRINTF(x) 53 | #endif 54 | 55 | #ifdef GLOBALS 56 | #define GLOBAL(a) a 57 | #define GLOBAL_INIT(a,b) a = b 58 | #else 59 | #define GLOBAL(a) extern a 60 | #define GLOBAL_INIT(a,b) extern a 61 | #endif 62 | 63 | struct request { 64 | unsigned short id; 65 | 66 | struct sockaddr_in client; 67 | unsigned short clientid; 68 | unsigned char recursion; 69 | 70 | struct event timeout; 71 | 72 | struct request **prev; 73 | struct request *next; 74 | }; 75 | 76 | GLOBAL_INIT(unsigned int authoritative_port, 53); 77 | GLOBAL_INIT(unsigned int authoritative_timeout, 10); 78 | GLOBAL_INIT(unsigned int recursive_port, 53); 79 | GLOBAL_INIT(unsigned int recursive_timeout, 90); 80 | GLOBAL_INIT(unsigned int stats_timeout, 3600); 81 | GLOBAL_INIT(unsigned int port, 53); 82 | 83 | GLOBAL(char *authoritative); 84 | GLOBAL(char *chrootdir); 85 | GLOBAL(char *listenat); 86 | GLOBAL(char *recursive); 87 | GLOBAL(char *user); 88 | 89 | GLOBAL(unsigned long active_queries); 90 | GLOBAL(unsigned long all_queries); 91 | GLOBAL(unsigned long authoritative_queries); 92 | GLOBAL(unsigned long recursive_queries); 93 | GLOBAL(unsigned long removed_queries); 94 | GLOBAL(unsigned long dropped_queries); 95 | GLOBAL(unsigned long answered_queries); 96 | GLOBAL(unsigned long dropped_answers); 97 | GLOBAL(unsigned long late_answers); 98 | GLOBAL(unsigned long hash_collisions); 99 | 100 | /* dnsproxy.c */ 101 | void signal_handler(int, short, void *); 102 | 103 | /* daemon.c */ 104 | int daemon(int, int); 105 | 106 | /* hash.c */ 107 | void hash_add_request(struct request *); 108 | void hash_remove_request(struct request *); 109 | struct request *hash_find_request(unsigned short); 110 | 111 | /* internal.c */ 112 | int add_internal(char *); 113 | int is_internal(struct in_addr); 114 | 115 | /* log.c */ 116 | void log_syslog(const char *); 117 | void info(const char *, ...); 118 | void error(const char *, ...); 119 | void fatal(const char *, ...); 120 | 121 | /* parse.c */ 122 | int parse(const char *); 123 | 124 | /* statistics.c */ 125 | void statistics_start(void); 126 | 127 | #endif /* _DNSPROXY_H_ */ 128 | -------------------------------------------------------------------------------- /hash.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include "dnsproxy.h" 25 | 26 | #define HASHSIZE 10 27 | #define HASH(id) (id & ((1 << HASHSIZE) - 1)) 28 | 29 | static struct request *request_hash[1 << HASHSIZE]; 30 | 31 | void 32 | hash_add_request(struct request *req) 33 | { 34 | struct request **p = &request_hash[HASH(req->id)]; 35 | 36 | if ((req->next = *p) != NULL) { 37 | (*p)->prev = &req->next; 38 | ++hash_collisions; 39 | } 40 | *p = req; 41 | req->prev = p; 42 | 43 | ++active_queries; 44 | } 45 | 46 | void 47 | hash_remove_request(struct request *req) 48 | { 49 | if (!req->prev) return; 50 | if (req->next) 51 | req->next->prev = req->prev; 52 | *req->prev = req->next; 53 | req->prev = NULL; 54 | 55 | --active_queries; 56 | } 57 | 58 | struct request * 59 | hash_find_request(unsigned short id) 60 | { 61 | struct request *req = request_hash[HASH(id)]; 62 | 63 | for (;;) { 64 | if (!req) break; 65 | if (req->id == id) break; 66 | req = req->next; 67 | } 68 | 69 | return req; 70 | } 71 | -------------------------------------------------------------------------------- /internal.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "dnsproxy.h" 29 | 30 | struct internal { 31 | unsigned int addr; 32 | unsigned int mask; 33 | struct internal *next; 34 | }; 35 | 36 | static struct internal *internals = NULL; 37 | 38 | int 39 | add_internal(char *s) 40 | { 41 | char *p; 42 | int mask; 43 | struct in_addr addr; 44 | struct internal *ipa; 45 | 46 | if (s == NULL) 47 | return 0; 48 | 49 | if ((p = strchr(s, '/')) != NULL) { 50 | mask = strtol(p+1, NULL, 10) % 32; 51 | *p = '\0'; 52 | } else { 53 | mask = 32; 54 | } 55 | 56 | if (inet_pton(AF_INET, s, &addr) != 1) 57 | return 0; 58 | 59 | if ((ipa = calloc(1, sizeof(struct internal))) == NULL) 60 | fatal("calloc: %s", strerror(errno)); 61 | 62 | memcpy(&ipa->addr, &addr, 4); 63 | ipa->mask = htonl(0xffffffff << (32 - mask)); 64 | ipa->addr &= ipa->mask; 65 | ipa->next = internals; 66 | internals = ipa; 67 | 68 | DPRINTF(("add_internal %s/%d (%08x/%08x)\n", inet_ntoa(addr), mask, 69 | ipa->addr, ipa->mask)); 70 | 71 | return 1; 72 | } 73 | 74 | int 75 | is_internal(struct in_addr arg) 76 | { 77 | unsigned int addr; 78 | struct internal *p; 79 | 80 | DPRINTF(("is_internal(%s)\n", inet_ntoa(arg))); 81 | memcpy(&addr, &arg, 4); 82 | 83 | for (p = internals; p != NULL; p = p->next) { 84 | DPRINTF(("%08x == %08x & %08x ?\n", p->addr, addr, p->mask)); 85 | if (p->addr == (addr & p->mask)) 86 | return 1; 87 | } 88 | 89 | return 0; 90 | } 91 | -------------------------------------------------------------------------------- /log.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004,2005 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "dnsproxy.h" 29 | 30 | static int log_on_syslog = 0; 31 | 32 | void 33 | log_syslog(const char *tag) 34 | { 35 | openlog(tag, LOG_NDELAY, LOG_DAEMON); 36 | ++log_on_syslog; 37 | } 38 | 39 | static void 40 | log_printf(int level, const char *fmt, va_list ap) 41 | { 42 | if (log_on_syslog) 43 | vsyslog(level, fmt, ap); 44 | else { 45 | (void)vfprintf(stderr, fmt, ap); 46 | if (strchr(fmt, '\n') == NULL) 47 | fprintf(stderr, "\n"); 48 | } 49 | } 50 | 51 | void 52 | info(const char *fmt, ...) 53 | { 54 | va_list ap; 55 | 56 | va_start(ap, fmt); 57 | log_printf(LOG_INFO, fmt, ap); 58 | va_end(ap); 59 | } 60 | 61 | void 62 | error(const char *fmt, ...) 63 | { 64 | va_list ap; 65 | 66 | va_start(ap, fmt); 67 | log_printf(LOG_ERR, fmt, ap); 68 | va_end(ap); 69 | } 70 | 71 | void 72 | fatal(const char *fmt, ...) 73 | { 74 | va_list ap; 75 | 76 | va_start(ap, fmt); 77 | log_printf(LOG_ERR, fmt, ap); 78 | va_end(ap); 79 | 80 | exit(1); 81 | } 82 | -------------------------------------------------------------------------------- /parse.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "dnsproxy.h" 28 | 29 | /* parse -- Simple configuration file parser. Takes a filename and 30 | * reads pairs of 'key value' or 'key = value'. 31 | */ 32 | 33 | int 34 | parse(const char *fname) 35 | { 36 | FILE *f; 37 | char buf[1024]; 38 | char *s, *key, *arg; 39 | 40 | if ((f = fopen(fname, "r")) == NULL) 41 | return 0; 42 | 43 | while (fgets(buf, sizeof(buf), f) != NULL) { 44 | 45 | if ((s = strchr(buf, '#')) != NULL) 46 | *s = '\0'; 47 | 48 | key = strtok(buf, " \t="); 49 | arg = strtok(NULL, " \t\n"); 50 | if (!key || !arg) 51 | continue; 52 | 53 | DPRINTF(("Found key '%s' arg '%s'\n", key, arg)); 54 | 55 | if (!strcmp(key, "authoritative")) { 56 | authoritative = strdup(arg); 57 | continue; 58 | } 59 | if (!strcmp(key, "authoritative-timeout")) { 60 | authoritative_timeout = strtol(arg, NULL, 10); 61 | continue; 62 | } 63 | if (!strcmp(key, "authoritative-port")) { 64 | authoritative_port = strtol(arg, NULL, 10); 65 | continue; 66 | } 67 | if (!strcmp(key, "recursive")) { 68 | recursive = strdup(arg); 69 | continue; 70 | } 71 | if (!strcmp(key, "recursive-timeout")) { 72 | recursive_timeout = strtol(arg, NULL, 10); 73 | continue; 74 | } 75 | if (!strcmp(key, "recursive-port")) { 76 | recursive_port = strtol(arg, NULL, 10); 77 | continue; 78 | } 79 | if (!strcmp(key, "statistics")) { 80 | stats_timeout = strtol(arg, NULL, 10); 81 | continue; 82 | } 83 | if (!strcmp(key, "listen")) { 84 | listenat = strdup(arg); 85 | continue; 86 | } 87 | if (!strcmp(key, "port")) { 88 | port = strtol(arg, NULL, 10); 89 | continue; 90 | } 91 | if (!strcmp(key, "chroot")) { 92 | chrootdir = strdup(arg); 93 | continue; 94 | } 95 | if (!strcmp(key, "user")) { 96 | user = strdup(arg); 97 | continue; 98 | } 99 | if (!strcmp(key, "internal")) { 100 | add_internal(arg); 101 | continue; 102 | } 103 | 104 | info("Unable to parse '%s'", buf); 105 | } 106 | 107 | fclose(f); 108 | 109 | return 1; 110 | } 111 | -------------------------------------------------------------------------------- /stats.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2003,2004 Armin Wolfermann 3 | * 4 | * Permission is hereby granted, free of charge, to any person obtaining a 5 | * copy of this software and associated documentation files (the "Software"), 6 | * to deal in the Software without restriction, including without limitation 7 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 | * and/or sell copies of the Software, and to permit persons to whom the 9 | * Software is furnished to do so, subject to the following conditions: 10 | * 11 | * The above copyright notice and this permission notice shall be included in 12 | * all copies or substantial portions of the Software. 13 | * 14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 20 | * DEALINGS IN THE SOFTWARE. 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include "dnsproxy.h" 27 | 28 | static struct event timeout; 29 | static struct timeval tv; 30 | 31 | /* ARGSUSED */ 32 | static void 33 | statistics_timeout(int fd, short event, void *arg) 34 | { 35 | /* reschedule timer event */ 36 | if (event_add(&timeout, &tv) == -1) 37 | fatal("event_add: %s", strerror(errno)); 38 | 39 | /* print statistics */ 40 | info("ActiveQr AuthorQr RecursQr AllQuery Answered"); 41 | info("%8ld %8ld %8ld %8ld %8ld", active_queries, authoritative_queries, 42 | recursive_queries, all_queries, answered_queries); 43 | info("TimeoutQ DroppedQ DroppedA LateAnsw HashColl"); 44 | info("%8ld %8ld %8ld %8ld %8ld", removed_queries, dropped_queries, 45 | dropped_answers, late_answers, hash_collisions); 46 | } 47 | 48 | void 49 | statistics_start(void) 50 | { 51 | if (stats_timeout > 0) { 52 | tv.tv_sec=stats_timeout; 53 | tv.tv_usec=0; 54 | 55 | evtimer_set(&timeout, statistics_timeout, NULL); 56 | if (evtimer_add(&timeout, &tv) == -1) 57 | fatal("evtimer_add: %s", strerror(errno)); 58 | } 59 | } 60 | --------------------------------------------------------------------------------