unifi-utilities / unifios-utilities

A collection of enhancements for UnifiOS based devices
GNU General Public License v3.0
3.9k stars 419 forks source link

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

Closed Kopernikus1979 closed 1 year ago

Kopernikus1979 commented 3 years ago

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"  
        }
      }
    }
  }
}
renedis commented 3 years ago

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.

Kopernikus1979 commented 3 years ago

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"  
        }
renedis commented 3 years ago

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
Tntdruid commented 3 years ago

Can you do that whit more than 1 IP?

Kopernikus1979 commented 3 years ago

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 :-)

boostchicken commented 3 years ago

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 commented 3 years ago

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

Kopernikus1979 commented 3 years ago

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?

EntropySmoke commented 3 years ago

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 commented 3 years ago

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

Kopernikus1979 commented 3 years ago

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

oliversl commented 2 years ago

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

untergeek commented 2 years ago

@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.

jiriteach commented 2 years ago

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

oliversl commented 2 years ago

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.

crsang commented 1 year ago

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

Kopernikus1979 commented 1 year ago

@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
crsang commented 1 year ago

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.

Kopernikus1979 commented 1 year ago

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
  }
}
crsang commented 1 year ago

Nice solution. Thanks for the help!

Kopernikus1979 commented 1 year ago

Edited my post with the scripts

boostchicken commented 1 year ago

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

crsang commented 1 year ago

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

crsang commented 1 year ago

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

Kopernikus1979 commented 1 year ago

@crsang

Hi,

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