OpenVPN with DNSMasq -- solution and question

Use this forum to share your network setup and what's been working for you.
Post Reply
hankofthehell
OpenVpn Newbie
Posts: 5
Joined: Wed Aug 06, 2014 1:24 pm

OpenVPN with DNSMasq -- solution and question

Post by hankofthehell » Wed Aug 06, 2014 2:02 pm

Hey everyone,

In addition to being still pretty new with networking technology, this is also my very first time using OpenVPN server (Debian 7 Stable). Recently, I had an issue where my OpenVPN Client (Android) wouldn't read the DNS addresses file; this file functions as an Ad/Tracker blacklist (ie, "address=/pr0n.edu/127.0.0.1").

I solved it by having dnsmasq listen on the P-t-P address:

Code: Select all

/etc/dnsmasq.conf
[...]
listen=10.8.0.2
But, the problem is that I don't really know why this works; I'm posting this in hopes that someone can better explain what's happening, or offer another solution. Despite a couple weeks' worth of research (on my downtime between two jobs), I've actually found close to nothing regarding the integration of dnsmasq and openvpn (that which I did find did not work); and, indeed, my shot-in-the-dark solution was not one I found anywhere online. Using what knowledge I could find, I had assumed that OpenVPN would automatically use the DNSMasq values without further configuration. In addition, I don't know why listening on eth0's IP (192.168.0.3) wouldn't have solved it since, I would assume, OpenVPN's traffic would pass through that in order to reach the internet. But, again, this dilemma is merely a testament to what little knowledge I have about these networking technologies, so any clarification would be appreciated.

My second question is, will listening on the P-t-P address, in and of itself, introduce any security risks of which I should be aware? I ask only because, again, I haven't found any information regarding my solution, so I don't want to miss anything that would be obvious to more seasoned network administrators.

Thanks a bunch.

hankofthehell
OpenVpn Newbie
Posts: 5
Joined: Wed Aug 06, 2014 1:24 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by hankofthehell » Sat Sep 06, 2014 12:11 am

I am so sorry it has taken so long to reply. Not long (days) after making that post, I was hired out of the blue for a full-time job, and I've been consumed by that ever since. Now that I have a moment to breathe, I just want to follow-up.
debbie10t wrote: For linux based systems, if you push DNS servers to the client you also need to run /etc/openvpn/update-resolv-conf like so:

Client.conf:
Code:
script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf

This may negate the need for your solution (I do not personally know for Android, perhaps you can test)
Android doesn't have an /etc/openvpn or /system/etc/openvpn folder :\ so, I'm not sure if this would be beneficial at all. In addition, the OpenVPN app doesn't seem to include this as an option.
IE: Do not use "listen={tun.IP.Add}" :: Try the script above.
Out of curiosity, why not? So far, I've found a few tutorials about using dnsmasq with openvpn which recommend setting "listen=127.0.0.1,10.8.0.1" in dnsmasq.conf; why would this not be a valid solution (or would it be more appropriate for me to ask this in a dnsmasq forum)?

I do appreciate the help and advice, however. I want to believe that I'll have a little more free time in the future.

hankofthehell
OpenVpn Newbie
Posts: 5
Joined: Wed Aug 06, 2014 1:24 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by hankofthehell » Sat Sep 06, 2014 7:17 pm

Code: Select all

script-security 2
up /etc/openvpn/update-resolv-conf
down /etc/openvpn/update-resolv-conf
Alright, so I don't know why this hadn't dawned on me earlier. In Linux, your three parameters would simply pass custom commands through resolvconf, which I neither use nor have installed. But, since I use dhclient, I needed only to add the following parameter to /etc/dhcp/dhclient.conf (on the client pc):

Code: Select all

prepend domain-name-servers 10.8.0.1
Because Android has its own way of doing this (ie, it doesn't have an /etc/resolv.conf file), it makes sense that your client.conf parameters would be unusable on my phone. I speculate that the OpenVPN app has some native way of solving this issue, but I cannot say for sure.

I suppose we were discussing two sides of a similar coin XD

Also, thanks for the diagram. I admit that I didn't get it at first, but it actually helped clear things up quite a bit.

hankofthehell
OpenVpn Newbie
Posts: 5
Joined: Wed Aug 06, 2014 1:24 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by hankofthehell » Sat Sep 06, 2014 8:59 pm

debbie10t wrote:
hankofthehell wrote: In Linux, your three parameters would simply pass custom commands through resolvconf, which I neither use nor have installed. But, since I use dhclient, I needed only to add the following parameter to /etc/dhcp/dhclient.conf (on the client pc):
Code:
prepend domain-name-servers 10.8.0.1
Does this work properly .. Would you say this feels like a more "elegant" solution ?
I would not be the person to judge whether this is more 'elegant' than resolvconf, but it does work fine for me on Debian (stable). In other readings, I've found instances where resolvconf can interfere with functionality, so I really haven't had much reason to use it. I'm open to new ideas, though.

hankofthehell
OpenVpn Newbie
Posts: 5
Joined: Wed Aug 06, 2014 1:24 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by hankofthehell » Sat Sep 13, 2014 5:32 pm

One final note. If any linux users are running NetworkManager/nm-applet (default in Gnome/*buntu and other popular distros), it has a GUI plugin that will automatically set-up the VPN and solve DNS issues. However, NetworkManager also has a tendency to override a lot of settings, so keep that in mind as well. But it is an easy, straightforward solution.

BernardC
OpenVpn Newbie
Posts: 2
Joined: Tue May 12, 2020 5:42 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by BernardC » Tue May 12, 2020 6:21 pm

I would like to share the way I finally got Ubuntu 20.04 to work with OpenVPN.
I first tried to get it to work with systemd sh...t but really this resolver can't work. You have to symbolically link /etc/resolv.conf to a file and then sometimes the system decides that the tunnel dns come first, sometimes not... My problem was therefore that, as my ISP DNS server can resolve some host, they send me a public IP, while actually, I use the VPN to be on the same LAN as the server, which will then present an admin interface...
Once I had the issue, there was really no way to push the right DNS to be first, so I went back to something I know well, dnsmasq.

This being said, let's get to business.

In Ubuntu 20.04, dnsmasq relies on a default config that can be overridden by files that you place in "/etc/dnsmasq.d/"
This offers an option to do some really nice things even with several tun{x} interfaces.

The excerpts below are just a first draft, but you'll understand the idea.

Based on the files "update-resolv-conf", I made my own "update-dnsmasq-conf" script as follows:

Code: Select all

#!/bin/bash
# 
# Parses DHCP options from openvpn to update dnsmasq.d configuration
# To use set as 'up' and 'down' script in your openvpn *.conf:
# up /etc/openvpn/scripts/update-dnsmasq-conf
# down /etc/openvpn/scripts/update-dnsmasq-conf
#
# Used snippets of resolvconf script by Thomas Hood and Chris Hanson.
# Licensed under the GNU GPL.  See /usr/share/common-licenses/GPL. 
# 
# Example envs set from openvpn:
#
#     foreign_option_1='dhcp-option DNS 193.43.27.132'
#     foreign_option_2='dhcp-option DNS 193.43.27.133'
#     foreign_option_3='dhcp-option DOMAIN be.bnc.ch'
#

[ "$script_type" ] || exit 0
[ "$dev" ] || exit 0

CONFIG_FILE="/etc/dnsmasq.d/test2.test"

split_into_parts()
{
	part1="$1"
	part2="$2"
	part3="$3"
}

case "$script_type" in
  up)
	NMSRVRS=""
	SRCHS=""
	foreign_options=$(printf '%s\n' ${!foreign_option_*} | sort -t _ -k 3 -g)
	for optionvarname in ${foreign_options} ; do
		option="${!optionvarname}"
		echo "$option"
		split_into_parts $option
		if [ "$part1" = "dhcp-option" ] ; then
			if [ "$part2" = "DNS" ] ; then
				NMSRVRS="${NMSRVRS:+$NMSRVRS }$part3"
			elif [ "$part2" = "DOMAIN" ] ; then
				SRCHS="${SRCHS:+$SRCHS }$part3"
			fi
		fi
	done
        # for some reason the $NMSRVRS struct is badly made. I 
        # cannot access one server at a time as all are in ${NMSRVRS[0]}
        split_into_parts $NMSRVRS
        S=""
        [ "$SRCHS" ] && S="server=/$SRCHS/$part1 #test
"
        echo -n "$S" > $CONFIG_FILE
	for NS in $NMSRVRS ; do
        	R="${R}server=$NS
"
	done
        echo -n "$R" >> $CONFIG_FILE
        ;;
  down)
        rm -f $CONFIG_FILE
	;;
esac

I have now a doubt whether or not this works properly, as I saw this:

Code: Select all

bernard@bernard-Latitude-D630:/etc/openvpn/scripts$ service dnsmasq status
● dnsmasq.service - dnsmasq - A lightweight DHCP and caching DNS server
     Loaded: loaded (/lib/systemd/system/dnsmasq.service; enabled; vendor preset: enabled)
     Active: active (running) since Tue 2020-05-12 17:08:53 CEST; 3h 3min ago
    Process: 24826 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS)
   Main PID: 684 (dnsmasq)
      Tasks: 1 (limit: 4645)
     Memory: 1.8M
     CGroup: /system.slice/dnsmasq.service
             └─684 /usr/sbin/dnsmasq -x /run/dnsmasq/dnsmasq.pid -u dnsmasq -7 /etc/dnsmasq.d,.dpkg-dist,.dpkg-old,.dpkg-new --local-servic>

Mai 12 17:08:53 bernard-Latitude-D630 dnsmasq[684]: using nameserver 192.168.0.1#53
Mai 12 17:08:53 bernard-Latitude-D630 dnsmasq[684]: using nameserver 172.16.0.204#53
Where the first entry is actually hard coded... in a different file of the same folder, so I don't know why it is first...

Basically, if you choose to prefix your file with a numerical ID (e.g. a calling argument), you can select the order in which the files will be read, and hence, the order of the DNS servers to be used when one or more tunnels are up (If I understood correctly, last comes first -> We could surely improve the solution above, as it will predominantly use the secondary server).

BernardC
OpenVpn Newbie
Posts: 2
Joined: Tue May 12, 2020 5:42 pm

Re: OpenVPN with DNSMasq -- solution and question

Post by BernardC » Thu May 14, 2020 11:16 pm

Hi again,
I found a more elegant solution relying on the networkmanagerdispatcher
see here: https://www.thegeekdiary.com/linux-os-s ... ispatcher/

I wrote the following script:

Code: Select all

#!/usr/bin/env bash
  
interface=$1
event=$2

echo "$interface received $event" | systemd-cat -p info -t dnsmasq_updater_script

if [ "$event" = "connectivity-change" ]; then
    exit 0;
fi

if [ -z "$interface" ]; then
    echo "$0: called with no interface" 1>&2
    exit 1;
fi

CONFIG_FILE="/etc/dnsmasq.d/$interface.test"

split()
{
# Takes 3 arguments:
# 1. String
# 2. separator
# 3. store variable name
#
# stores the parts of string in an array stored in variable "$3"
#

if [ -z "$3" ]; then
    exit 1;
fi
sep="$2"
string="$1"
readarray -td"$sep" $3 <<<"$string$sep"; unset "$3[-1]";
#declare -p $3;
}

dnsmasq_reload()
{
    echo "Reloading dnsmasq" | systemd-cat -p info -t dnsmasq_updater_script
    /etc/init.d/dnsmasq stop
    /etc/init.d/dnsmasq start
}

# IP4_NAMESERVERS: The variable contains a space-separated list of the DNS servers.
# IP4_DOMAINS    : The variable contains a space-separated list of the search domains.
#S='' #DOMAIN
#R='' #DNS

add_config_ini_lines()
{
# Takes 3 or more arguments:
# 1. path of config
# 2. config ini variable name
# 3. list of values expanded as "${arr[@]}"
#
# add the values to the end of path in an ini like format
#

local dollar1=$1
shift
local dollar2=$1
shift
local arr=("$@")
  for NS in "${arr[@]}"; do
    R="${R}$dollar2$NS
"
  done
  echo -n "$R" >> $dollar1
}

add_DN_config()
{
# Takes 4 or more arguments:
# 1. path of config
# 2. Config.ini like variable name
# 3. The primary DNS for the domain
# 4. list of Domains values expanded as "${arr[@]}"
#
# add the values to the end of path in an ini like format
#

local dollar1=$1
shift
local dollar2=$1
shift
local dollar3=$1
shift
local arr=("$@")
  for SD in "${arr[@]}"; do
    S="${S}$dollar2/$SD/$dollar3
"
  done
  echo -n "$S" >> $dollar1
}

#if [[ "$interface" == *"tun0"* ]]
if [[ "$interface" == "enp9s0" ]] || [[ "$interface" == "wlp12s0" ]]
then
    case "$event" in
        up)
        logger -s "NM Script up triggered"
        #command1
        split "$IP4_DOMAINS" " " "SRCHS"
        split "$IP4_NAMESERVERS" " " "NMSRVRS"
        # Arrays containing this info
        add_DN_config "$CONFIG_FILE" "server=" "$NMSRVRS" "${SRCHS[@]}"
        add_config_ini_lines "$CONFIG_FILE" "server=" "${NMSRVRS[@]}"
        dnsmasq_reload
        ;;
        down)
        logger -s "NM Script down triggered"
        #command2
        rm -f "$CONFIG_FILE"
        dnsmasq_reload
        ;;
#        pre-up)
#        logger -s "NM Script pre-up triggered"
#        #command3
#        ;;
#        post-down)
#        logger -s "NM Script post-down triggered"
#        #command4
#        ;;
#        dhcp4-change|dhcp6-change)
#       logger -s "NM Script change triggered"
#        # Do nothing
#        ;;
        *)
        ;;
    esac
fi

I didn't test with tun interfaces, but IMHO, it should work.

Post Reply