Search:  
Gentoo Wiki

Chroot/Dnsmasq

This article is part of the HOWTO series.
Installation Kernel & Hardware Networks Portage Software System X Server Gaming Non-x86 Emulators Misc

Contents

Introduction

Purpose

This document describes, how you can put dnsmasq in a chroot jail. Under normal circumstances one won't need this, because the program serves only trusted local LAN clients, and no one gets access from the internet.

But maybe someone runs dnsmasq which gets accessed from untrusted clients. There may happen an attack from a cracked server from the DMZ. Other scenarios like an open W-LAN are possible. Putting dnsmasq in a chroot jail should make your server a bit more secure

Scope

This HOWTO gives some expansion to the dnsmasq boot scripts, so dnsmasq is automatically put in chroot on startup. The document refers to version 2.22 of dnsmasq in the Gentoo repository.

Acronyms

DMZ 
De-Militarized Zone


Setup

Requirements

You need to emerge dnsmasq:

emerge -a dnsmasq

The chroot command used is already included in Gentoo

1st test

At first test, if your service is running properly. Start the service by running

/etc/init.d/dnsmasq start

and do some queries with "host" or "dig" directed to your nameserver. You need to make sure, that your services like DNS or DHCP work this way to get a testcase to compare to the chrooted service.

NOTE: It may be obvious, but during this time, your service is running without chroot restrictions. Take any steps needed to prevent access from untrusted clients.

Now stop the service and go on with setting up the chroot environment.

Setup the environment

Next is trying to put the program in a chroot jail. Make up a decent directory (e.g. /chroot/dnsmasq/) and copy the configurations file and runtime libs into, along with the related path. The directory tree should look like this afterwards

/chroot/dnsmasq/etc
/chroot/dnsmasq/etc/dnsmasq.conf
/chroot/dnsmasq/etc/hosts
/chroot/dnsmasq/etc/ppp
/chroot/dnsmasq/etc/ppp/resolv.conf
/chroot/dnsmasq/etc/passwd
/chroot/dnsmasq/etc/nsswitch.conf
/chroot/dnsmasq/etc/group
/chroot/dnsmasq/etc/localtime
/chroot/dnsmasq/etc/passwd.bak
/chroot/dnsmasq/etc/group.bak
/chroot/dnsmasq/etc/resolv.conf.bak
/chroot/dnsmasq/var
/chroot/dnsmasq/var/lib
/chroot/dnsmasq/var/lib/misc
/chroot/dnsmasq/var/lib/misc/dnsmasq.leases
/chroot/dnsmasq/var/db
/chroot/dnsmasq/var/run
/chroot/dnsmasq/var/run/dnsmasq.pid
/chroot/dnsmasq/usr
/chroot/dnsmasq/usr/sbin
/chroot/dnsmasq/usr/sbin/dnsmasq
/chroot/dnsmasq/lib
/chroot/dnsmasq/lib/libc.so.6
/chroot/dnsmasq/lib/ld-linux.so.2
/chroot/dnsmasq/lib/libnss_compat.so.2
/chroot/dnsmasq/lib/libnsl.so.1

To test the setup, call dnsmasq in the chroot environment with your usual options and check its running, e.g.

chroot /chroot/dnsmasq /usr/sbin/dnsmasq --user=named --group=named

Check that all needed libs are provided and the directories got write access where needed.

You may get an error claiming dnsmasq "failed to seed the random number generator" if that is the case, you also need to create the urandom and/or the random character device. Run the following command as root, and substitute in your chroot directory.

mknod -m 0644 ${CHROOT_DIR}/dev/random c 1 8
mknod -m 0644 ${CHROOT_DIR}/dev/urandom c 1 9

Expanding the boot scripts

Your boot script now does the same like in the test, execpt it tests for a valid environment, and copies all libs and config files to the chroot directory. If you did compile some libs anew e.g. during emerge -uD world, you only need to restart your service to get the new libs and binaries in the chroot dir.

File: /etc/init.d/dnsmasq
#!/sbin/runscript
# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License, v2 or later
# $Header: /var/cvsroot/gentoo-x86/net-dns/dnsmasq/files/dnsmasq-init,v 1.8 2006
/01/09 12:21:39 avenj Exp $

opts="${opts} reload"

depend() {
        provide dns
        need net
}


checkconfig() {

        # test for chroot env

        if [ "${DNSMASQ_USE_CHROOT}" == "yes" ] ; then
                if [ -z "${DNSMASQ_CHROOT_DIR}" ] ; then
                        eerror "You specified dnsmasq to run with chroot,"
                        eerror " but didn't give a directory in DNSMASQ_CHROOT_DIR."
                        eerror "Please update /etc/conf.d/dnsmasq"
                        return 1
                fi

                if [ ! -d ${DNSMASQ_CHROOT_DIR} ] ; then
                        eerror "\"${DNSMASQ_CHROOT_DIR}\" is no directory."
                        eerror "Please update DNSMASQ_CHROOT_DIR in /etc/conf.d/dnsmasq"
                        return 1
                fi

                if [ "`/bin/ls -id ${DNSMASQ_CHROOT_DIR}/ | /bin/cut -d' ' -f1`" == "`/bin/ls -id / | /bin/cut -d' ' -f1`" ] ; then
                        eerror "\"${DNSMASQ_CHROOT_DIR}\" points to root directory."
                        eerror "Please update DNSMASQ_CHROOT_DIR in /etc/conf.d/dnsmasq"
                        return 1
                fi

                if [ -z "${DNSMASQ_USER}" ] ; then
                        eerror "You have to give a user, else chroot makes no sense."
                        eerror "Please update DNSMASQ_USER in /etc/conf.d/dnsmasq"
                        return 1
                fi

                if ! /bin/id ${DNSMASQ_USER} > /dev/null 2>&1 ; then
                        eerror "Unknown user \"${DNSMASQ_USER}\"."
                        eerror "Please update DNSMASQ_USER in /etc/conf.d/dnsmasq"
                        return 1
                fi

                if [ -n "${DNSMASQ_GROUP}" ] ; then
                        if ! /bin/cut -d ':' -f1 /etc/group | /bin/grep -wq ${DNSMASQ_GROUP} ; then
                                eerror "Group ${DNSMASQ_GROUP} no found."
                                eerror "Please update DNSMASQ_GROUP in /etc/conf.d/dnsmasq"
                                return 1
                        fi
                fi

        fi

}



start() {
        local ret


        if ! checkconfig ; then
                eend 1
                return 1
        fi

        if [ "${DNSMASQ_USE_CHROOT}" == "yes" ] ; then

                ebegin "Starting dnsmasq in chroot environment"

                  # make a symlink to find it later on
                /bin/ln -sf ${DNSMASQ_CHROOT_DIR}/var/run/dnsmasq.pid /var/run/dnsmasq.pid

                 # get uid and gid
                DNSMASQ_OPTS="${DNSMASQ_OPTS} --user=${DNSMASQ_USER}"
                if [ -z "${DNSMASQ_GROUP}" ] ; then
                        DNSMASQ_GROUP="`/bin/id -gn ${DNSMASQ_USER}`"
                fi
                DNSMASQ_OPTS="${DNSMASQ_OPTS} --group=${DNSMASQ_GROUP}"


                 # prepare chroot env

                 # make directories
                for A in /etc/ppp /lib /usr/sbin; do
                        if [ ! -d ${DNSMASQ_CHROOT_DIR}/${A} ] ; then
                                if ! /bin/mkdir -p ${DNSMASQ_CHROOT_DIR}/${A} ; then
                                        eerror "Can not create directory ${DNSMASQ_CHROOT_DIR}/${A}. Bailing out"
                                        eend 1
                                        return 1
                                fi
                        fi
                done

                 # copy files
                #for A in /etc/dnsmasq.conf /etc/localtime /etc/hosts /etc/nsswitch.conf /etc/resolv.conf ; do
                for A in /etc/dnsmasq.conf /etc/localtime /etc/hosts /etc/nsswitch.conf ; do
                        if ! /bin/cp -aLf ${A} ${DNSMASQ_CHROOT_DIR}/etc/. ; then
                                eerror "Can not copy \"${A}\" to ${DNSMASQ_CHROOT_DIR}/etc/. Bailing out"
                                eend 1
                                return 1
                        fi
                done

                #if ! /bin/cp -aLf  /etc/dnsmasq.d/resolv.conf ${DNSMASQ_CHROOT_DIR}/etc/dnsmasq.d/. ; then
                #       eerror "Can not copy \"/etc/dnsmasq.d/resolv.conf\" to ${DNSMASQ_CHROOT_DIR}/etc/dnsmasq.d/. Bailing out"
                #       eend 1
                #       return 1
                #fi

                for A in /lib/ld-linux.so.2 /lib/libc.so.6 /lib/libnsl.so.1 /lib/libnss_compat.so.2 ; do
                        if ! /bin/cp -aLf ${A} ${DNSMASQ_CHROOT_DIR}/lib/.; then
                                eerror "Can not copy \"${A}\" to ${DNSMASQ_CHROOT_DIR}/lib/. Bailing out"
                                eend 1
                                return 1
                        fi
                done


                 # again test for chroot dir in "/"
                 # this is a security measure to prevent stipping /etc/passwd of root account
                if [ "`/bin/ls -id ${DNSMASQ_CHROOT_DIR}/ | /bin/cut -d' ' -f1`" == "`/bin/ls -id / | /bin/cut -d' ' -f1`" ] ; then
                        eerror "\"${DNSMASQ_CHROOT_DIR}\" points to root directory."
                        eerror "In danger of erasings parts of the password data base, exiting"
                        eend 1
                        return 1
                fi

                if [ -f ${DNSMASQ_CHROOT_DIR}/etc/passwd ] ; then
                        /bin/mv -f ${DNSMASQ_CHROOT_DIR}/etc/passwd ${DNSMASQ_CHROOT_DIR}/etc/passwd.bak
                fi
                /bin/grep -w ${DNSMASQ_USER} /etc/passwd > ${DNSMASQ_CHROOT_DIR}/etc/passwd
                if [ -f ${DNSMASQ_CHROOT_DIR}/etc/group ] ; then
                        /bin/mv -f ${DNSMASQ_CHROOT_DIR}/etc/group ${DNSMASQ_CHROOT_DIR}/etc/group.bak
                fi
                /bin/grep -w ${DNSMASQ_GROUP} /etc/group > ${DNSMASQ_CHROOT_DIR}/etc/group

                /bin/cp -aLf /usr/sbin/dnsmasq ${DNSMASQ_CHROOT_DIR}/usr/sbin/.

                 # temporary disable socket create restriction
                if [ -w /proc/sys/kernel/grsecurity/chroot_caps ]; then
                        echo 0 > /proc/sys/kernel/grsecurity/chroot_caps
                fi

                 # start in chroot
                /bin/chroot ${DNSMASQ_CHROOT_DIR} /usr/sbin/dnsmasq -x /var/run/dnsmasq.pid ${DNSMASQ_OPTS}
                ret=$?

                 # reenable socket create restriction
                if [ -w /proc/sys/kernel/grsecurity/chroot_caps ]; then
                        sleep 1
                        echo 1 > /proc/sys/kernel/grsecurity/chroot_caps
                fi
        else
                ebegin "Starting dnsmasq"
                /usr/sbin/dnsmasq -x /var/run/dnsmasq.pid ${DNSMASQ_OPTS}
                ret=$?
        fi
        eend $ret
}

stop() {
        ebegin "Stopping dnsmasq"
        start-stop-daemon --stop --quiet --pidfile /var/run/dnsmasq.pid
          # remove maybe dangling symlink from chroot environment
        /bin/rm -f /var/run/dnsmasq.pid
        eend $?
}

reload() {
        ebegin "Reloading dnsmasq"
        kill -HUP $(< /var/run/dnsmasq.pid)
        eend $?
}

 

Configuration

Now change your configuration to run as user "named". Else your chroot setup wouldn't make much sense.

File: /etc/conf.d/dnsmasq
 # /etc/conf.d/dnsmasq: config file for /etc/init.d/dnsmasq
 
 # See the dnsmasq(8) man page for possible options to put here.
 DNSMASQ_OPTS=""
 
 # user & group replacement
 DNSMASQ_USER="named"
 DNSMASQ_GROUP="named"
 
 # run in chroot env
 DNSMASQ_USE_CHROOT="yes"
 
 # only valid if DNSMASQ_USE_CHROOT==yes above
 # 
 # chroot dir
 DNSMASQ_CHROOT_DIR="/chroot/dnsmasq/"
 


Dnsmasq has to know the position of the resolv.conf file. In this HOWTO I put it in /chroot/dnsmasq/etc/ppp/resolv.conf, but you can put it anywhere in the chrooted directory. Just let dnsmasq know where it is

File: /etc/dnsmasq.conf
 # Change this line if you want dns to get its upstream servers from
 # somewhere other that /etc/resolv.conf
 # NOTE: dont specify 2 files
 #resolv-file=/etc/resolv.conf
 resolv-file=/etc/ppp/resolv.conf
 

Here we don't put in the full path, more then the relative one to the chroot dir. This is because the chroot() syscall happens before the execution of dnsmasq, so it just sees "/chroot/dnsmasq" as "/"

Finish

Now start your service in chroot and add it to the boot sequence

/etc/init.d/dnsmasq start
rc-update add dnsmasq default

You're done!

Retrieved from "http://www.gentoo-wiki.info/Chroot/Dnsmasq"

Last modified: Fri, 03 Oct 2008 07:00:00 +0000 Hits: 9,477