Jigsaw-Code / outline-apps

Outline Client and Manager, developed by Jigsaw. Outline Manager makes it easy to create your own VPN server. Outline Client lets you share access to your VPN with anyone in your network, giving them access to the free and open internet.
https://getoutline.org/
Apache License 2.0
8.22k stars 1.35k forks source link

Allow custom DNS resolver in client #568

Open mrphs opened 5 years ago

mrphs commented 5 years ago

I've raised this problem a long while ago privately but considering it hasn't changed, I'm assuming it has been forgotten, hence opening this ticket.

Outline shouldn't hard-code DNS resolver in the client. Especially when using OpenDNS. Ideally, this should be an option that is set by the outline manager. Otherwise outline should route the DNS through outline-server. This has a few reasons:

Kolahzary commented 5 years ago

I totally agree with this request, Here in I.R.Iran i can't use Outline on my Android because government censored hard-coded DNS Servers inside outline client, I don't know how they do that but months ago DNS stopped working for mobile phones which run Outline. (means if I turn on Outline, apps which use DNS to resolve their server's IP address will stop working, but some apps like Telegram works because they have IP address of their servers hard-coded inside them)

By the way I'm currently using Simple DNSCrypt + Shadowsocks client on my Laptop and it works perfectly.

alalamav commented 5 years ago

Thank you for your feedback. We are open to considering this feature request. Since the client could easily override the DNS server set by the server admin (many apps use custom DNS resolvers), we are thinking of making a configurable option in the client. Perhaps the admin could set the default resolver in the invite.

mrphs commented 5 years ago

@alalamav Thanks for the response. I'd argue that those "many apps" you mentioned aren't probably routing the entire traffic of the device.

To be perfectly clear... I think it's ideal if it's configurable in "outline manager" and optionally possible to override by "outline client" if the users wishes to. Otherwise, considering most end users might not even know what DNS is, and that they already have trusted admin with their traffic, it might make sense to let the admin decide where the DNS requests should go.

alalamav commented 5 years ago

@mrphs, your proposal sounds reasonable to me.

The point I was trying to make is that there is no guarantee that a given app will use the system resolver set by Outline. They can always make DNS requests to the resolver of their choice and indeed many apps do.

mvonweis commented 5 years ago

Hi, this has become quite urgent as of today. I'm operating four servers in three different countries, and OpenDNS has stopped responding to all of them.

modib commented 5 years ago

@alalamav

  1. An app not using system resolver is beyond the control of the user without port 53 traffic forwarding, so it could be ignored for now.
  2. The Outline client should always rely on outline server to provide a list of DNS servers to be configured for client. The server can have a default list like the opendns servers or 9.9.9.9 that could be easily changed via outline manager. For non-technical users setting custom DNS servers via client is not something they should have to know. Technical users will always know how to override it.
  3. Truly stealth option would be to embed a DNS-over-https(DoH) client with a localhost resolver on client side querying a DoH server on outline server side that uses an upstream DNS server configurable via outline manager. e.g. https://github.com/m13253/dns-over-https
mvonweis commented 5 years ago

I don't think Shadowsocks has a mechanism for setting the DNS servers, as it seems to be only a transparent proxy. The client needs to somehow understand which DNS servers to use. The Outline developers have made the simplest possible choice: the DNS servers are hardcoded into the Outline client. If these servers don't work for you, you're out of luck.

The simplest solution I can see is to make the DNS IP addresses changeable through extra URL arguments such as "?dns1=9.9.9.9&dns2=1.1.1.1". This looks sensible to me and is also backwards-compatible.

There could also be a UI element or a json/xml/plist file for users to manually change the DNS servers on the client side. You could also add to the server Docker image a simple httpd daemon that returns a dnsconfig.json file that the client can parse. And if I've understood SS properly (possibly not) you could also set up dnsmasq on the server Docker image, and hardcode the client to use this instead.

This is mostly a problem on the Mac where overriding Outline's default DNS servers is a tough exercise. I'd rather fix the problem properly than write scripts to work around it.

Omoeba commented 5 years ago

Just make a script called “routedns.sh” in your root directory using sudo nano /root/routedns.sh And paste in the following

#!/bin/bash

/sbin/iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to “outline-server-external-ipv4”:53;
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to “outline-server-external-ipv4”:53;
/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE;
/sbin/ip6tables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to [“outline-server-external-IPv6”]:53;
/sbin/ip6tables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to [“outline-server-external-IPv6”]:53;
/sbin/ip6tables -t nat -A POSTROUTING -j MASQUERADE

exit 0

And then type sudo chmod +x /root/routedns.sh

Then type sudo nano /etc/rc.local And paste in this

#!/bin/bash

bash /root/routedns.sh

exit 0

Finally, type sudo chmod +x /etc/rc.local And enable rc-local by typing sudo systemctl enable rc-local

This will route all dns traffic to the outline server. I tested this on a DigitalOcean Ubuntu 18.04 droplet. This might not work on other vps providers and distros.

modib commented 5 years ago

@mvonweis The README on outline-server says

This repository has all the code needed to create and manage Outline servers on DigitalOcean. An Outline server runs instances of Shadowsocks proxies and provides an API used by the Outline Manager application.

Outline server install script installs 2 containers - the API for outline manager and the shadowsocks server.

The outline manager API can be extended to also allow defining a default set of nameservers that could be served to all the outline clients.

@Omoeba Thanks for the shell script but I don't think it fits neatly in the way outline-server, outline-manager and outline-client has been designed. Plus the script is not portable to windows and mac.

Omoeba commented 5 years ago

@modib what do you mean by not portable?

mvonweis commented 5 years ago

@modib Correct, but this requires modifying three components instead of one. The Manager app is so limited that out only works for trivial setups.

@omoeba The iptables script only works on Linux. Porting it to Mac or Windows requires rewriting the whole script.

Omoeba commented 5 years ago

The script is meant to be run on the server, not the client.

asteriskyg commented 5 years ago

Just make a script called “routedns.sh” in your root directory using sudo nano /root/routedns.sh And paste in the following

#!/bin/bash

/sbin/iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to “outline-server-external-ipv4”:53;
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to “outline-server-external-ipv4”:53;
/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE;
/sbin/ip6tables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to [“outline-server-external-IPv6”]:53;
/sbin/ip6tables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to [“outline-server-external-IPv6”]:53;
/sbin/ip6tables -t nat -A POSTROUTING -j MASQUERADE

exit 0

And then type sudo chmod +x /root/routedns.sh

Then type sudo nano /etc/rc.local And paste in this

#!/bin/bash

bash /root/routedns.sh

exit 0

Finally, type sudo chmod +x /etc/rc.local And enable rc-local by typing sudo systemctl enable rc-local

This will route all dns traffic to the outline server. I tested this on a DigitalOcean Ubuntu 18.04 droplet. This might not work on other vps providers and distros.

@Omoeba I'm sorry but I'm not good at iptables... so could you write some example codes with example ip for me?

Omoeba commented 5 years ago

@ASTERISK-Git this will route all dns to cloudflare’s DNS at https://1.1.1.1/dns/

#!/bin/bash

/sbin/iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE;
/sbin/ip6tables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A POSTROUTING -j MASQUERADE

exit 0
fortuna commented 3 years ago

I hear the need to specify the DNS resolver to be used. That should be specified by the managers, as general users don't know how to do that.

I like the idea of the server running its own resolver. Then the client could be changed to try :53 first. Or perhaps a special address like dns.local, since Shadowsocks allows for domain addresses.

What should this server resolver look like? I see at least two options:

Thoughts?

cc: @bemasc

fortuna commented 3 years ago

Clarifying some implementation options.

DNS Wiring

A) Run a stub resolver on the Client's localhost that forwards the queries to dns.local (or some other pre-defined domain) via a Shadowsocks proxy connection. The server would intercept dns.local and forward to the designated resolver. Configure the VPN to use the localhost address as the DNS resolver. B) Configure the VPN to use as the primary DNS resolver. Change server to resolve DNS on :53 using the designated resolver. C) Fetch some DNS config with the address of the designated resolver from the server on connection and configure the VPN with that. D) Hardcode the designated DNS resolver on the invite. Can't be changed later.

In A-C the Client needs to check if the resolver supports DNS resolution. For backward compatibility, we can check that in the connectivity test and fallback to the existing behavior on failure. Similar to how we fallback DNS to TCP if UDP is blocked.

(D) is probably the easiest, but cannot be changed. (C) is probably a good compromise of simplicity and flexibility A-B is compatible with third-party Shadowsocks clients that allow specifying the IP of the resolver.

Server designated resolver

There are a few options for the designated resolver: A) Run own recursive resolver B) Use the host's system resolver C) Use a third-party resolver, specified somehow by the admin. This is similar to (B), since the admin can change the system resolver.

bemasc commented 3 years ago

One interesting consideration here is that, if the VPN advertises the IP of a good third-party resolver, Android DoT and Chrome DoH might be able to upgrade to encrypted DNS. This improves the user's privacy with respect to the proxy server, and also has nontrivial performance and reliability implications (perhaps good, perhaps bad).

I think the best balance of simplicity and flexibility might be to place the proxy's recommended DNS server in a shadowsocks online-config JSON blob, and avoid changing the behavior of ss:// access keys (which would continue to use client-hardcoded resolvers).

One tricky thing here is that Chrome DoH needs to see the third-party IP as the configured DNS server, so we would need to reconfigure the VPN interface after receiving the latest shadowsocks config.

hilt86 commented 3 years ago

@fortuna is there any workaround that can give us some control over the resolver until a solution is finished? The only option I can think of atm is adding an upstream firewall and using NAT to force UDP dns traffic to a server of my choosing..

RebelliousWhiz commented 3 years ago

@ASTERISK-Git this will route all dns to cloudflare’s DNS at https://1.1.1.1/dns/

#!/bin/bash

/sbin/iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE;
/sbin/ip6tables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A POSTROUTING -j MASQUERADE

exit 0

Hi @Omoeba, I think iptables -t nat -A POSTROUTING -j MASQUERADE might be not necessary in my case?

I checked the codes here, the outline appears to use OpenDNS, Cloudflare, and Quad9.

// OpenDNS, Cloudflare, and Quad9 DNS resolvers' IP addresses. 
private static final String[] DNS_RESOLVER_IP_ADDRESSES = {
      "208.67.222.222", "208.67.220.220", "1.1.1.1", "9.9.9.9"};

So I just manipulated with those DNS by:

#! /bin/bash

# outline will try to use TCP if UDP is not available for DNS.
iptables -t nat -A OUTPUT -d 208.67.222.222/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 208.67.220.220/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 1.1.1.1/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 9.9.9.9/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53

iptables -t nat -A OUTPUT -d 208.67.222.222/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 208.67.220.220/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 1.1.1.1/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 9.9.9.9/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53

Without `iptables -t nat -A POSTROUTING -j MASQUERADE`` it works fine. I can see tcpdump log in the system.

Without (before) iptables rules, I see the outline is using the shadowsocks-rust server to make the connection to the DNS server (1.1.1.1) directly. tcpdump is not getting anything.

After ipbtales (now), tcpdump is catching the log which should means the host server is making the connection without the shadowsocsks-rust server involve.

My environment: Ubuntu 18.04.5 shadowsocks-rust server (shouldn't matter?)

RebelliousWhiz commented 3 years ago

By the way, I think both shadowsocks-libev and shadowsocks-rust servers have the ability to define DNS server for traffic. It really doesn't make sense why Outline can't... 😅

Omoeba commented 3 years ago

@ASTERISK-Git this will route all dns to cloudflare’s DNS at https://1.1.1.1/dns/

#!/bin/bash

/sbin/iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.1:53;
/sbin/iptables -t nat -A POSTROUTING -j MASQUERADE;
/sbin/ip6tables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to [2606:4700:4700::1111]:53;
/sbin/ip6tables -t nat -A POSTROUTING -j MASQUERADE

exit 0

Hi @Omoeba, I think iptables -t nat -A POSTROUTING -j MASQUERADE might be not necessary in my case?

I checked the codes here, the outline appears to use OpenDNS, Cloudflare, and Quad9.

// OpenDNS, Cloudflare, and Quad9 DNS resolvers' IP addresses. 
private static final String[] DNS_RESOLVER_IP_ADDRESSES = {
      "208.67.222.222", "208.67.220.220", "1.1.1.1", "9.9.9.9"};

So I just manipulated with those DNS by:

#! /bin/bash

# outline will try to use TCP if UDP is not available for DNS.
iptables -t nat -A OUTPUT -d 208.67.222.222/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 208.67.220.220/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 1.1.1.1/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 9.9.9.9/32 -p tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53

iptables -t nat -A OUTPUT -d 208.67.222.222/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 208.67.220.220/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 1.1.1.1/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
iptables -t nat -A OUTPUT -d 9.9.9.9/32 -p udp --dport 53 -j DNAT --to-destination 8.8.8.8:53

Without `iptables -t nat -A POSTROUTING -j MASQUERADE`` it works fine. I can see tcpdump log in the system.

Without (before) iptables rules, I see the outline is using the shadowsocks-rust server to make the connection to the DNS server (1.1.1.1) directly. tcpdump is not getting anything.

After ipbtales (now), tcpdump is catching the log which should means the host server is making the connection without the shadowsocsks-rust server involve.

My environment: Ubuntu 18.04.5 shadowsocks-rust server (shouldn't matter?)

Yeah the masquerade rules are completely unnecessary. I don't recommend using rc.local either since it's deprecated so use a @reboot cron job or even better, a simple systemd service ordered after the host's networking (network-online.target in most cases). To be completely honest, I'll probably disagree with the vast majority of recommendations I made 2 years ago so take everything here with a healthy dose of skepticism and make sure to do plenty of testing.

RebelliousWhiz commented 3 years ago

Thanks for the reply Omoeba! And yes, I am using a systemd .service file to manage this script. I am doing tons of testing here to make sure everything works fine...

Omoeba commented 3 years ago

Sounds good! So DNS resolvers are still hardcoded in the client 2 years later?

RebelliousWhiz commented 3 years ago

Yelp.... 🙄

Omoeba commented 3 years ago

That's unfortunate.

cjhenck commented 2 years ago

Since this came up in a net4people issue, I wanted to say that I think we'd be open to collaborating with a community member on a contribution to solve this.

Regarding @bemasc's suggestion, we are currently working on online config and so that may become possible in the next few months.

My guess (but @fortuna would have to weigh in) is that we'd want to start with the simplest approach first (such as using a forwarder on the server) before moving on to more advanced options (advertising a server-specified DNS server to the client and re-configuring the VPN connection).

nhutwelker commented 2 years ago

Just looking for a way to configure DoH or DoT 3rd party dns resolver on the outline server.

nirkons commented 2 years ago

+1 to set custom DNS or even local DNS instead of routing it through server

Zzombiee2361 commented 2 years ago

I'm using laravel valet which uses dnsmasq, I can't access my projects when outline is connected. Please add an option to disable outline DNS resolver entirely

shadyvb commented 2 years ago

After some fiddling, I noticed that shadowsocks has a Rust version that does support local-dns features, but it needed quite a bit of fiddling to try, since you need both the server and the client to use that Rust version if I'm not mistaken. And I'm not even sure if you can use local resolvers with it, but at least you can specify custom DNS servers.

At least there is hope!

For the time being, my workarounds was:

  1. Use a custom DNS on the server hosting outline itself.
  2. OR.. use a custom DNS server while bringing up the docker container of outline, which isn't easy if you're using the bash script directly. But it's possible if you hack it. Check out the --dns argument in Docker docs.
RebelliousWhiz commented 2 years ago

For people who wants more control over their traffic, here are projects I have been using and work great for me:

shadowsocks-rust as server.

I have been using shadowsocks-rust since last year. shadowsocks-libev has stopped the new-feature development. The shadowsocks community has moved the focus to shadowsocks-rust.

Shadowrocket as iOS client.

This is a very popular app for people in China. There are a few other similar apps, but this one is the long-existing one. Unfortunately, this app has been banned in China App Store.

This app gives you tons of abilities to control your traffic, but it takes quite a bit of understanding of this app. It does not come with a complete manual. You have to try the configs before you actually use them in the production.

Nevertheless, it's a great app, my daily life is depending on this app...

Clash and Clash for Windows for desktop environments. Clash for Android for Android (obviously).

Clash is a third-party core for shadowsocks. It supports various protocols. It's a very powerful tool to manipulate traffics, similar to Shadowrocket.

I hope this comment can do a little help to our brothers, sisters, and friends in Iran and other censorship-heavy countries.

avjoshi-07 commented 2 years ago

I see that the request to allow either the clients or the server administrators to determine their own DNS servers instead of hardcoding them into the client has been around for quite a while. Doesn't look like it's implemented yet, coz I have manually set the DNS to be Quad9 (9.9.9.9) on my iPad, but the moment I connect it to Outline VPN, it automatically changes from 9.9.9.9 to 1.1.1.1 (Cloudflare). How do I know this? Coz I tried to open a malicious website (foxlimited.top) which I know for sure is blocked by Quad9 but not by Cloudflare, and when I open that webpage while connected to Outline, it opens. And as soon as I disconnect my iPad from Outline, that webpage is blocked again.

Is there a timeline to when will this feature be implemented? I don't think it should take a lot of time.

daniellacosse commented 2 years ago

We're totally open to pull requests!

alamar commented 1 year ago

To all whom it may concern sudo chattr +i /etc/resolv.conf will protect a simple text file of DNS config and Outline will no longer overwrite it - make sure that file is not a symlink though.

dkoloditch commented 1 year ago

@alamar so you're saying we can make our custom DNS changes, then use chattr to set /etc/resolv.conf to be immutable and Outline will no longer overwrite the changes?

Fireycold commented 1 year ago

Clarifying some implementation options.

DNS Wiring

A) Run a stub resolver on the Client's localhost that forwards the queries to dns.local (or some other pre-defined domain) via a Shadowsocks proxy connection. The server would intercept dns.local and forward to the designated resolver. Configure the VPN to use the localhost address as the DNS resolver. B) Configure the VPN to use as the primary DNS resolver. Change server to resolve DNS on :53 using the designated resolver. C) Fetch some DNS config with the address of the designated resolver from the server on connection and configure the VPN with that. D) Hardcode the designated DNS resolver on the invite. Can't be changed later.

In A-C the Client needs to check if the resolver supports DNS resolution. For backward compatibility, we can check that in the connectivity test and fallback to the existing behavior on failure. Similar to how we fallback DNS to TCP if UDP is blocked.

(D) is probably the easiest, but cannot be changed. (C) is probably a good compromise of simplicity and flexibility A-B is compatible with third-party Shadowsocks clients that allow specifying the IP of the resolver.

Server designated resolver

There are a few options for the designated resolver: A) Run own recursive resolver B) Use the host's system resolver C) Use a third-party resolver, specified somehow by the admin. This is similar to (B), since the admin can change the system resolver.

Does option (D) currently work? If not, what changes would be required for (D) to work?

Fireycold commented 1 year ago

Since this came up in a net4people issue, I wanted to say that I think we'd be open to collaborating with a community member on a contribution to solve this.

Regarding @bemasc's suggestion, we are currently working on online config and so that may become possible in the next few months.

My guess (but @fortuna would have to weigh in) is that we'd want to start with the simplest approach first (such as using a forwarder on the server) before moving on to more advanced options (advertising a server-specified DNS server to the client and re-configuring the VPN connection).

Any update on the roadmap/release date for the online config feature?

romikkazan commented 1 year ago

For so many years, have you still not made it possible for at least the server administrator to specify DNS? This is very sad, as no workarounds described above work.

danielslyman commented 1 year ago

I'd love this too

fortuna commented 1 year ago

Prioritizing this has been a challenge, specially in face of the Iran crisis and Google layoffs. We prioritized features such as dynamic keys and prefix disguise, as well as significant server optimizations.

With the January 2023 layoffs, we lost half of the team.

We have very limited capacity, and we are now focused on providing a SDK to enable others to more easily create circumvention tool or to add circumvention capabilities to existing apps.

For the DNS solution, we would have to implement it for each different platform, in different languages, using different APIs, plus challenges with the user experience.

We are aiming to rewire the code so that the networking config can be passed directly to the Go networking code. That will make feature like this easier. Though the DNS server still have to be set up in the platform-specific VPN code, but the code will be cleaner in a way that it will be easier to take contributions. A basic implementation will be to specify the resolver in the access key.

Damassk commented 10 months ago

Is there any solution for this problem for the latest version of the server, because iptables no longer work, and chattr cannot be used due to the error: Operation not supported while reading flags on /etc/resolv.conf.

Maybe I'm not so good at administration, but some obvious simple means are not very helpful. An attempt to use dnsmasq also failed because port 53 was already taken.

alamar commented 10 months ago

@Damassk https://unix.stackexchange.com/questions/421977/how-to-set-chattr-i-for-my-etc-resolv-conf

navidlukas commented 5 months ago

The following IPTABLES confirmed works on Ubuntu 22 on Oracle Cloud

sudo iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.3:53; sudo iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.3:53;

I installed crontab

crontab -e @reboot sudo iptables -t nat -A OUTPUT -p tcp --dport 53 -j DNAT --to 1.1.1.3:53 @reboot sudo iptables -t nat -A OUTPUT -p udp --dport 53 -j DNAT --to 1.1.1.3:53

Now the above two lines are automatically added to firewall on startup after a reboot.