unifios-utilities icon indicating copy to clipboard operation
unifios-utilities copied to clipboard

Help converting config.gateway.json to a script to use with UDM Pro

Open Kopernikus1979 opened this issue 4 years ago • 11 comments

Hi,

At the moment I have an USG3 + CloudKeyGen2+ and I will migrate to an UDM Pro and use the udm-utilities as a replacement for my config.gateway.json below is my existing config, can someone help me on the way to make this working with my new udm pro? In the config I have 1. Static host mapping for my controller 2. MDNS for Trusted/IoT VLAN 3. NAT forward/DNS masquerade for my 2 RaspPi running Pi-Hole for devices (most Google speakers etc) who try to bypass my PiHole.

Thx!

{
  "system": {
    "static-host-mapping": {
      "host-name": {
        "mydomain.extension": {
          "alias": [
            "unifi"
          ],
          "inet": [
            "10.10.50.10"
          ]
        }
      }
    }
  },
  "service": {
    "mdns": {
      "repeater": {
        "interface": [
          "eth1.20",
          "eth1.10"
        ]
      }
    },
    "nat": {
      "rule": {
        "10": {
          "description": "Redirect Trusted VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.10",
          "inside-address": {
            "address": "10.10.10.5-10.10.10.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.10.5-10.10.10.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
		"20": {
          "description": "Redirect IoT VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.20",
          "inside-address": {
            "address": "10.10.20.5-10.10.20.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.20.5-10.10.20.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
		"30": {
          "description": "Redirect Guests VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.30",
          "inside-address": {
            "address": "10.10.30.5-10.10.30.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.30.5-10.10.30.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
        "6010": {
          "description": "MASQ Trusted VLAN DNS requests",
          "destination": {
            "address": "10.10.10.5-10.10.10.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.10",
          "protocol": "tcp_udp",
          "type": "masquerade"
        },
        "6020": {
          "description": "MASQ IoT VLAN DNS requests",
          "destination": {
            "address": "10.10.20.5-10.10.20.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.20",
          "protocol": "tcp_udp",
          "type": "masquerade"
		},
        "6030": {
          "description": "MASQ Guests VLAN DNS requests",
          "destination": {
            "address": "10.10.30.5-10.10.30.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.30",
          "protocol": "tcp_udp",
          "type": "masquerade"  
		}
      }
    }
  }
}

Kopernikus1979 avatar Mar 28 '21 10:03 Kopernikus1979

1. Static host mapping:

Create the following file

File: /mnt/data/on_boot.d/10SetMyHosts.sh

!/bin/sh

create my custom dnsmasq file cat > /run/dnsmasq.conf.d/mine.conf <<EOF host-record=udmp,gateway,192.168.1.1 host-record=host111,192.168.1.99 EOF

force restart of dnsmasq pkill dnsmasq

This will work across reboots & firmware upgrades (but not factory resets). I threw in the udmp & gateway line to show an example of multiple hostnames mapping to the same ip. To run the script without rebooting:

sh /mnt/data/on_boot.d/10SetMyHosts.sh I recommend that you keep a copy of the script somewhere off the UDMP in case you have to do a factory reset one day.

2. MDNS

3. DNS masquerade set this to the interface(s) on which you want DNS TCP/UDP port 53 traffic re-routed through the DNS container. separate interfaces with spaces. e.g. "br0" or "br0 br1" etc. FORCED_INTFC=""

Dit you even read the instructions or text on the main page? This is all available for a long time.

renedis avatar Mar 28 '21 17:03 renedis

1. Static host mapping:

Create the following file

File: /mnt/data/on_boot.d/10SetMyHosts.sh

!/bin/sh

create my custom dnsmasq file cat > /run/dnsmasq.conf.d/mine.conf <<EOF host-record=udmp,gateway,192.168.1.1 host-record=host111,192.168.1.99 EOF

force restart of dnsmasq pkill dnsmasq

This will work across reboots & firmware upgrades (but not factory resets). I threw in the udmp & gateway line to show an example of multiple hostnames mapping to the same ip. To run the script without rebooting:

sh /mnt/data/on_boot.d/10SetMyHosts.sh I recommend that you keep a copy of the script somewhere off the UDMP in case you have to do a factory reset one day.

2. MDNS

3. DNS masquerade set this to the interface(s) on which you want DNS TCP/UDP port 53 traffic re-routed through the DNS container. separate interfaces with spaces. e.g. "br0" or "br0 br1" etc. FORCED_INTFC=""

Dit you even read the instructions or text on the main page? This is all available for a long time.

1 & 2 are clear to me But with 3 it's not my intention to route all dns traffic to a dns container, in my existing gateway.config.json I made nat routing for my vlans for when a device tries to connect to dns port who is not one of my 2 PïHole's, and then the masquerade rules are used so the device is not aware that it is beign routed to PiHole instead of Google dns etc.

It's this sectional I would like to now a way to implement on the UDM Pro, also I want to keep using my 2 RasPi with PiHole instead of running PiHole on a container:

nat": {
      "rule": {
        "10": {
          "description": "Redirect Trusted VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.10",
          "inside-address": {
            "address": "10.10.10.5-10.10.10.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.10.5-10.10.10.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
		"20": {
          "description": "Redirect IoT VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.20",
          "inside-address": {
            "address": "10.10.20.5-10.10.20.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.20.5-10.10.20.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
		"30": {
          "description": "Redirect Guests VLAN DNS requests",
          "destination": {
            "port": "53"
          },
          "inbound-interface": "eth1.30",
          "inside-address": {
            "address": "10.10.30.5-10.10.30.6",
            "port": "53"
          },
          "source": {
            "address": "!10.10.30.5-10.10.30.6"
          },
          "log": "disable",
          "protocol": "tcp_udp",
          "type": "destination"
        },
        "6010": {
          "description": "MASQ Trusted VLAN DNS requests",
          "destination": {
            "address": "10.10.10.5-10.10.10.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.10",
          "protocol": "tcp_udp",
          "type": "masquerade"
        },
        "6020": {
          "description": "MASQ IoT VLAN DNS requests",
          "destination": {
            "address": "10.10.20.5-10.10.20.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.20",
          "protocol": "tcp_udp",
          "type": "masquerade"
		},
        "6030": {
          "description": "MASQ Guests VLAN DNS requests",
          "destination": {
            "address": "10.10.30.5-10.10.30.6",
            "port": "53"
          },
          "log": "disable",
          "outbound-interface": "eth1.30",
          "protocol": "tcp_udp",
          "type": "masquerade"  
		}

Kopernikus1979 avatar Mar 28 '21 19:03 Kopernikus1979

But with 3 it's not my intention to route all dns traffic to a dns container, in my existing gateway.config.json I made nat routing for my vlans for when a device tries to connect to dns port who is not one of my 2 PïHole's, and then the masquerade rules are used so the device is not aware that it is beign routed to PiHole instead of Google dns etc.

It's this sectional I would like to now a way to implement on the UDM Pro, also I want to keep using my 2 RasPi with PiHole instead of running PiHole on a container:

The script is not masquerading to a container, but to a IP address. You can remove the extra bits in the script to keep only the masquerade part.

Should look something like this for 1 pihole IP:

#!/bin/sh

IPV4_IP="YOUR-PIHOLE-IP"
IPV6_IP="YOUR-PIHOLE-IPv6"
FORCED_INTFC="br0"

for intfc in ${FORCED_INTFC}; do
  if [ -d "/sys/class/net/${intfc}" ]; then
    for proto in udp tcp; do
      prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j DNAT --to ${IPV4_IP}"
      iptables -t nat -C ${prerouting_rule} || iptables -t nat -A ${prerouting_rule}
      
      if [ -n "${IPV6_IP}" ]; then
        prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j DNAT --to ${IPV6_IP}"
        ip6tables -t nat -C ${prerouting_rule} || ip6tables -t nat -A ${prerouting_rule}
      fi
    done
  fi
done

renedis avatar Mar 29 '21 14:03 renedis

Can you do that whit more than 1 IP?

Tntdruid avatar Mar 29 '21 16:03 Tntdruid

Yes, also wondering how to do this for my second Pihole? Should I add a second script? Also with FORCED_INTFC="" should I define here every VLAN?

Now my Pi-Hole's are multihomed meaning they have an IP in every VLAN, but thinking of moving them to my Management VLAN1, the reason for this is because I read somewhere when you forwareded ip is not in the same subnet of your pihole the dnsmasq rule is not needed, is this correct?

@renedis could you help me plz... thx :-)

Kopernikus1979 avatar Apr 07 '21 18:04 Kopernikus1979

you can do this for any ip address, just make a new script like "99-iptables.sh" and then have it contain all your ip tables execs yuou want there.

boostchicken avatar Apr 09 '21 05:04 boostchicken

Also, ditch multi homed.that is one reason for sure.

boostchicken avatar Apr 09 '21 05:04 boostchicken

Also, ditch multi homed.that is one reason for sure.

Thx, did you mean by "one reason for sure" that by ditching the multihomed I don't need the dnsmasq rule?

Kopernikus1979 avatar Apr 10 '21 17:04 Kopernikus1979

A bit off-topic, but does UDM accept and honor all CLI commands that USG accepts and honors via config.gateway.json and/or CLI? Some commands don't seem to work at all for UDM. For example, Ubiquiti's CLI commands to stop LLDP (Link Layer Discovery Protocol) advertisement do not stop it. It may be a bug, but it is unknown to me.

Another example is: set service ubnt-discover disable set service ubnt-discover-server disable

UDM does not honor those commands and continues to perform device discovery via broadcast IP 255.255.255.255 UDP port 10001 (over LAN and even WAN), but developers say that it is a known bug in new firmware releases.

EntropySmoke avatar May 03 '21 20:05 EntropySmoke

Any luck with your conversion? I think the config file for UDM is the /config/ubios-udapi-server/ubios-udapi-server.state .

EntropySmoke avatar May 08 '21 16:05 EntropySmoke

All is working fine, however can't seem to get my seond PiHole working:

I have:

iptables -t nat -A PREROUTING -i br0 -p udp ! -s 10.10.1.5 ! -d 10.10.1.5 --dport 53 -j DNAT --to 10.10.1.5:53

but if I create a second script for:

iptables -t nat -A PREROUTING -i br0 -p udp ! -s 10.10.1.6 ! -d 10.10.1.6 --dport 53 -j DNAT --to 10.10.1.6:53

the second script will be ignored if I have a dns lookup on the second PiHole

In gateway.config.json I could set as source !10.10.1.5-10.10.1.6 and as destination 10.10.1.5-10.10.1.6

How to acomplish this? I can ofcourse ditch the second PiHole....

Thx

Kopernikus1979 avatar Aug 03 '21 05:08 Kopernikus1979

Directory /mnt/data/on_boot.d/ does not existe anymore as of firmware from today

oliversl avatar Oct 01 '22 21:10 oliversl

@oliversl which firmware is that? I upgraded my UDM Pro to 1.12.30 several days ago and /mnt/data/on_boot.d/ is very much still there and worked at startup for me.

untergeek avatar Oct 01 '22 23:10 untergeek

1.12.30 is the latest even for early adopter and all working for me.

jiriteach avatar Oct 02 '22 00:10 jiriteach

My fault, looks like the folder /mnt/data/on_boot.d/ is created by a custom user script. On a vanilla UDM SE, in the /mnt/data/ folder, there is no on_boot.d folder.

oliversl avatar Oct 03 '22 22:10 oliversl

I'm still struggling with making this work on the UDMP. @Kopernikus1979 where you able to find a scripted solution?

crsang avatar May 31 '23 14:05 crsang

@crsang

Hi,

Yes, first install the UDM boot script: https://github.com/unifi-utilities/unifios-utilities/blob/main/on-boot-script/README.md

Then add (and adjust to your needs) this script "force-dns-10.sh":

#!/bin/sh
 
### Add iptables rules to redirect port 53 traffic (tcp+udp)
### IPv4 DNS traffic is redirected to $IPV4_IP on port $IPV4_PORT
### IPv6 DNS traffic is redirected to $IPV6_IP on port $IPV6_PORT
 
## DNS redirect configuration variables:
IPV4_IP="10.10.100.50"
IPV4_PORT=53
# Leave this blank if you don't use IPv6
IPV6_IP=
IPV6_PORT=53
 
# Set this to the interfaces you want to force through the DNS IP.
# Separate interfaces with spaces.
# e.g. "br0" or "br0 br1" etc.
FORCED_INTFC="br0 br10 br20 br30 br40 br50 br60 br70"
 
# Enable this if your pihole is on the same subnet as the devices/interfaces
# you are forwarding. This will allow the return traffic to work on the same
# subnet, but will make the pihole think the requests are coming from the router.
# You will lose client information in the pihole dashboard if you enable this.
# It is preferable to put the pihole on a different subnet and disable this.
ENABLE_MASQUERADE=0
 
# IPv4 force DNS (TCP/UDP 53) through DNS container
for intfc in ${FORCED_INTFC}; do
  if [ -d "/sys/class/net/${intfc}" ]; then
    for proto in udp tcp; do
      prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4_IP} ! -d ${IPV4_IP} --dport 53 -j DNAT --to ${IPV4_IP}:${IPV4_PORT}"
      iptables -t nat -C ${prerouting_rule} || iptables -t nat -A ${prerouting_rule}
 
      # IPv6 force DNS (TCP/UDP 53) through DNS container
      if [ -n "${IPV6_IP}" ]; then
        prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6_IP} ! -d ${IPV6_IP} --dport 53 -j DNAT --to ${IPV6_IP}:${IPV6_PORT}"
        ip6tables -t nat -C ${prerouting_rule} || ip6tables -t nat -A ${prerouting_rule}
      fi
    done
  fi
done
 
if [ "$ENABLE_MASQUERADE" = "1" ]; then
  for proto in udp tcp; do
    postrouting_rule="POSTROUTING ! -s ${IPV4_IP} -d ${IPV4_IP} -p ${proto} --dport 53 -j MASQUERADE"
    iptables -t nat -C ${postrouting_rule} || iptables -t nat -A ${postrouting_rule}
  done
fi


Kopernikus1979 avatar May 31 '23 15:05 Kopernikus1979

Fantastic.

Were you able to get it working for two pi-holes? I, like you, have two and would like both to act similar but not interfere with each other.

crsang avatar May 31 '23 15:05 crsang

I use two pihole's but in a HA config, I use keepalived so my 10.10.100.50 is my virtual IP of keepalived who refers to 10.10.100.51 as my main pihole and 10.10.100.52 as backup, and then I use gravity-sync to keep them in sync.

Master:

global_defs {
  router_id pihole-dns-01
  script_user root
  enable_script_security
}

vrrp_script chk_pihole {
  script "/usr/local/scripts/check-pihole"
  interval 1
  weight -100
}

vrrp_instance Pi-hole-Master {
  state MASTER
  interface eth0
  virtual_router_id 55
  priority 150
  advert_int 1
  unicast_src_ip 10.10.100.51
  unicast_peer {
    10.10.100.52
  }

  authentication {
    auth_type PASS
    auth_pass secret
  }

  virtual_ipaddress {
    10.10.100.50/24
  }

  track_script {
    chk_pihole
  }
}

Backup:

global_defs {
  router_id pihole-dns-02
  script_user root
  enable_script_security
}

vrrp_script chk_pihole {
  script "/usr/local/scripts/check-pihole"
  interval 1
  weight -100
}

vrrp_instance Pi-hole-Backup {
  state BACKUP
  interface eth0
  virtual_router_id 55
  priority 140
  advert_int 1
  unicast_src_ip 10.10.100.52
  unicast_peer {
    10.10.100.51
  }

  authentication {
    auth_type PASS
    auth_pass secret
  }

  virtual_ipaddress {
    10.10.100.50/24
  }

  track_script {
    chk_pihole
  }
}

Kopernikus1979 avatar May 31 '23 15:05 Kopernikus1979

Nice solution. Thanks for the help!

crsang avatar May 31 '23 15:05 crsang

Edited my post with the scripts

Kopernikus1979 avatar May 31 '23 15:05 Kopernikus1979

Wow, thanks for coming back after all this time. Feel free to send a PR to the repo with your scripts!

boostchicken avatar May 31 '23 19:05 boostchicken

@Kopernikus1979 Did you have to add a rule to the UDM to allow VRRP traffic? My keepalived is flapping between master/backup.

crsang avatar Jun 06 '23 16:06 crsang

I removed the unicast lines from your keepalived configs and the flapping stopped. Not sure why multicast works and unicast did not.

crsang avatar Jun 06 '23 18:06 crsang

@crsang

Hi,

No rule, but both my pihole's are on their own Pi-Hole VLAN.

Kopernikus1979 avatar Jun 07 '23 09:06 Kopernikus1979