What's new

SBS. Script for using sing-box on Asus routers with Merlin firmware.

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

Could it be that dnsmasq is intercepting traffic on port 53 before it is processed by iptables?
Nope, prerouting happens before that.

You should be able to watch packet count by
Code:
iptables -t nat -nvL PREROUTING
and
Code:
iptables -t nat -nvL SINGBOXDNS
send some dns requests from this ip and run them again and see if the counter goes up. (Also you could post the output here so we can se they turned out ok)
 
All clients are assigned DNS via the router's dhcp. This is the IP address of the home Linux server with Adguard Home installed on it.
Wait, you advertise a local linux server as dns to your lan? This may be trouble as even though the data passes the router, lan to lan is not routed, it's switched. This means this data won't reach router firewall and our firewall rules will not do anything.
If this is the case it's nothing you can do about it, except advertise another dns to your clients.

It is indeed possible to advertise router as dns then use dnsdirector to globally redirect to your Linux server. This way your lan will still use dns on Linux server but you would be able to intercept it with firewall rules.

Anyway, your setup is your setup and perhaps not typical for your script users. You can't take care of all users different setps.
 
Wait, you advertise a local linux server as dns to your lan? This may be trouble as even though the data passes the router, lan to lan is not routed, it's switched. This means this data won't reach router firewall and our firewall rules will not do anything.
If this is the case it's nothing you can do about it, except advertise another dns to your clients.

It is indeed possible to advertise router as dns then use dnsdirector to globally redirect to your Linux server. This way your lan will still use dns on Linux server but you would be able to intercept it with firewall rules.

Anyway, your setup is your setup and perhaps not typical for your script users. You can't take care of all users different setps.
You are right. If i remove DNS servers in LAN DHCP and enable "Advertise router's IP in addition to user-specified DNS" there, then everything starts working as intended. This suits me quite well. I will implement this in a script in the future.
 
It's the same, you just add the port to translate to:
Code:
 #create new chain and flush it
iptables -t nat -N SINGBOXDNS
iptables -t nat -F SINGBOXDNS 2>/dev/null

#create record for dns to jump to this chain:
iptables -t nat -I PREROUTING -p tcp -m tcp --dport 53 -j SINGBOXDNS
iptables -t nat -I PREROUTING -p udp -m udp --dport 53 -j SINGBOXDNS

#setup source ip rules for redirect dns:
iptables -t nat -A SINGBOXDNS -s 192.168.50.45 -j DNAT --to-destination <singbox_tun_ip>:portnr
iptables -t nat -A SINGBOXDNS -s 192.168.50.102 -j DNAT --to-destination <singbox_tun_ip>:portnr
#more rules from different source ips could be added here.
I plan to use ipset to create an iptables rule for all the listed ip addresses.
Code:
iptables -t nat -N SINGBOXDNS
iptables -t nat -F SINGBOXDNS 2>/dev/null

iptables -t nat -I PREROUTING -p tcp -m tcp --dport 53 -j SINGBOXDNS
iptables -t nat -I PREROUTING -p udp -m udp --dport 53 -j SINGBOXDNS

ipset create myset hash:ip
ipset add myset 192.168.50.33
ipset add myset 192.168.50.34
ipset add myset 192.168.50.35

iptables -t nat -A SINGBOXDNS -m set --match-set myset src -p udp -j DNAT --to-destination 172.19.0.1:5553
iptables -t nat -A SINGBOXDNS -m set --match-set myset src -p tcp -j DNAT --to-destination 172.19.0.1:5553
Do you know if there are any events happening in the router system that could remove ipset from memory?
And is it possible to replace -A with -I in the last two commands? To get by with one function in the script code instead of two.
And is it necessary to add
Code:
2>/dev/null
at the end of the second command?
And why clear the chain immediately after its creation? It might not be empty?
 
Last edited:
I plan to use ipset to create an iptables rule for all the listed ip addresses.
That's a great idea! If I may propose to use hash:net instead... it would allow you to use cidr notation to cover entirely or parts of network. https://github.com/ZebMcKayhan/WireguardManager?tab=readme-ov-file#create-and-setup-ipsets


Do you know if there are any events happening in the router system that could remove ipset from memory?
Nope, only the firewall rules. The ipsets are left alone until reboot.


And is it possible to replace -A with -I in the last two commands? To get by with one function in the script code instead of two.
The -I Inserts the rule on top of the list while -A Appends the rule in the bottom. Sure, either way, since there are no other rules. This is more important for filter tables. Rules are processed from top first and bottom last.

And is it necessary to add
Code:
2>/dev/null
at the end of the second command?
If the command is for precaution only it may generate an error. This hide the error from printing

If you are now using ipsets it feel unnecessary to create your own chain. These 2 rules should cover it:
Code:
iptables -t nat -I PREROUTING -p tcp -m set --match-set myset src -m tcp --dport 53 -j DNAT --to-destination 172.19.0.1:5553
iptables -t nat -I PREROUTING -p udp -m set --match-set myset src -m udp --dport 53 -j DNAT --to-destination 172.19.0.1:5553
But you may need to test first.

Making your own chain makes more sense if you will clutter it with lots of rules, but with ipsets it will only ever be these 2.
 
Last edited:
If I may propose to use hash:net instead... it would allow you to use cidr notation to cover entirely or parts of network.
OK.
These 2 rules should cover it:
Code:
iptables -t nat -I PREROUTING -p tcp -m set --match-set myset src -m tcp --dport 53 -j DNAT --to-destination 172.19.0.1:5553
iptables -t nat -I PREROUTING -p udp -m set --match-set myset src -m udp --dport 53 -j DNAT --to-destination 172.19.0.1:5553
But you may need to test first.
I tested it. Everything works as expected.
Thank you.
 
OK.

I tested it. Everything works as expected.
Thank you.
Great!

While you are into using ipsets, you could handle routing using the same ipset, so an entry in the ipset takes care of both routing and dns. Routing cannot be done directly with ipset, but letting firewall mark matching packets, ip rule... could be setup for marked packets so end result would be the same. https://www.snbforums.com/threads/u...ute-domains-to-a-vpn-client.41560/post-351450
I.e
Code:
ip rule add from 0/0 fwmark 0x1000/0x1000 table $ROUTE_TABLE
iptables -t mangle -A PREROUTING  -m set --match-set myset src -j MARK --set-mark 0x1000/0x1000

Not sure it adds any value though...
 
Last edited:
While you are into using ipsets, you could handle routing using the same ipset, so an entry in the ipset takes care of both routing and dns. Routing cannot be done directly with ipset, but letting firewall mark matching packets, ip rule... could be setup for marked packets so end result would be the same. https://www.snbforums.com/threads/u...ute-domains-to-a-vpn-client.41560/post-351450
I.e
I've thought about it too. But I've decided not to get involved with fwmark for now. I don't like him for some reason).
Here's what's bothering me now. Solving one problem revealed another. The script works fine if any public DNS server is specified in the sing-box configuration file. But if instead of it I specify the address of the home Linux server with Adguard Home, which is also located in the router network, then resolving stops working and sites do not open. As if DNS requests from sing-box cannot get to the Linux server with Adguard Home. Any thoughts on this?
 
Any thoughts on this?
No idea... doesn't seem like anything in the firewall preventing this.
I don't know the inner working of singbox. Would it be aware that your lan ip suppose to go out locally and not sent over the tunnel? Perhaps you need to add your lan ip range to some singbox config file?

One thought I had was that your lan doesn't have a route in the policy table and since you didn't use the suppress_prefixlength 0 routing rule these are the type of issues you could expect. But I'm not sure this is it in this case.
 
No idea... doesn't seem like anything in the firewall preventing this.
I don't know the inner working of singbox. Would it be aware that your lan ip suppose to go out locally and not sent over the tunnel? Perhaps you need to add your lan ip range to some singbox config file?

One thought I had was that your lan doesn't have a route in the policy table and since you didn't use the suppress_prefixlength 0 routing rule these are the type of issues you could expect. But I'm not sure this is it in this case.
In the sing-box configuration file, the first outbound is used by default to direct DNS requests to the specified DNS server. For me, the first is "direct", that is, DNS requests to the DNS server should go to the local network, and not to the tunnel. But it is possible to forcibly specify where exactly DNS requests to a specific DNS server should go, and I specified "direct", but this also had no effect.
When I tried sing-box on one of the virtual Linux machines, it resolved its DNS requests on the home Linux server with Adguard Home without any problems. This problem appeared only with sing-box on the router.
At the same time, the router itself works without problems with this Adguard Home, the IP address of which is indicated as a DNS server in the WAN section.
It is also worth mentioning the fact that I have access to all local resources from a computer whose traffic goes through the sing-box installed on the router. But DNS requests from the sing-box to Adguard Home cannot get through.
Maybe the router itself thinks that they should be sent to the Internet, and not to the local network?
 
Last edited:
It was an interesting and useful experience with an attempt to implement the use of DNS servers specified in the sing-box configuration file. But too many shortcomings. For starters, the problem I noticed yesterday is that sing-box cannot use Adguard Home installed in my home network as a DNS server. Now I have discovered that my mobile phone, connected via WiFi, cannot open any sites, apparently because DNS does not work properly for it. My laptop, also connected via WiFi, opens sites, but I have to wait a very long time. At the same time, the desktop, connected by wire, has no problems with DNS. The script code has become significantly more complicated, the instructions for users will also become more complicated and will require more actions from them, which means there will be more mistakes from inexperienced users. In my opinion, this implementation of using sing-box with DNS servers specified in its configuration file has more disadvantages than benefits. As a result, I decided to put yesterday's work in the archive. Maybe I'll come back to them someday.
 
I decided to put yesterday's work in the archive. Maybe I'll come back to them someday.
Your call. But it would be interesting to see if you execute at the prompt:
Code:
ip rule add from all lookup main suppress_prefixlength 0
Then run
Code:
ip rule
And check so this rule ends up below the rule pointing to table local and above your custom rules.

Usually script writers make scripts that assumes router is used for dns and either modifies dnsmasq.conf or make firewall rules. Other configs are usually up to the user to fix themselves, but this forum is here to help them if needed. Some scripts checks this by i.e reading nvram variables and warns the user, but no script will fix any user config for you.
 
Last edited:
And check so this rule ends up below the rule pointing to table local and above your custom rules.
Code:
0:      from all lookup local
79:     from all lookup main suppress_prefixlength 0
80:     from 192.168.50.49 lookup 555
81:     from 192.168.50.48 lookup 555
82:     from 192.168.50.47 lookup 555
83:     from 192.168.50.45 lookup 555
84:     from 192.168.50.43 lookup 555
85:     from 192.168.50.42 lookup 555
86:     from 192.168.50.38 lookup 555
87:     from 192.168.50.33 lookup 555
88:     from 192.168.50.32 lookup 555
89:     from 192.168.50.31 lookup 555
90:     from all to 10.6.0.5 lookup main
90:     from all to 10.6.0.6 lookup main
90:     from all to 10.6.0.7 lookup main
11210:  from 192.168.50.40 lookup wgc1
11211:  from 192.168.50.39 lookup wgc1
32766:  from all lookup main
32767:  from all lookup default
Right?
 
Command "from" is unknown, try "ip rule help".
Maybe I need
Yep, forgot the 'add', updated now.


Looks good!

It will make all specific routes, like routes to your lan, guest wifi, other interfaces you may have be accessible for who ever uses policy tables, but not prefix 0 (default route for unknown destinations like internet). It may have som drawbacks but simple way to test if routing is your issue with failed dns lookup.
 
Yep, forgot the 'add', updated now.



Looks good!

It will make all specific routes, like routes to your lan, guest wifi, other interfaces you may have be accessible for who ever uses policy tables, but not prefix 0 (default route for unknown destinations like internet). It may have som drawbacks but simple way to test if routing is your issue with failed dns lookup.
Adguard Home IP address as DNS in sing-box still does not work.
And for a mobile phone connected via WiFi, this did not change anything.

By the way, with the DNS request redirection method from Adguard Home it works for my mobile phone too, but with iptables it works only for the desktop.
I checked it on my wife's iPhone - the result is the same as with my Android phone.

This is what I don't understand. All devices are in the same subnet. But those connected via WIFI either can't get responses to DNS requests, or take a very long time to get them. And a desktop connected via a wire doesn't have such problems. Without implementing everything we achieved yesterday, everything works without problems. But the great capabilities of sing-box for managing DNS requests are not implemented.
 
Last edited:
This is what I don't understand. All devices are in the same subnet. But those connected via WIFI either can't get responses to DNS requests, or take a very long time to get them. And a desktop connected via a wire doesn't have such problems.
It may not at all be about how they are connected it could be device os and how fast they are to switch to alternative dns or methods perhaps. Or have you tested this?

I wonder if we broke dns lookup from your Linux server when we set dns director global direction to linux server. Even the linux server (AGH) dns lookups would be redirected back to itself. Unless you set it to use DoT or DoH.
Perhaps things will change if you add a rule in dns director for your linux server and set it to "no redirection".
 
when we set dns director global direction to linux server.
I have never used DNS Director. I always have it turned off. I redirected DNS requests from the required devices from AGH to the required IP address and port in the web interface of AGH itself.
And I have assigned only DoH servers as upstream resolvers in AGH.
Or I misunderstood you.
 
Last edited:
I have never used DNS Director. I always have it turned off. I redirected DNS requests from the required devices from AGH to the required IP address and port in the web interface of AGH itself.
And I have assigned only DoH servers as upstream resolvers in AGH.
Or I misunderstood you.
No, this was the info I was looking for. So that's not it then.
It's difficult to debug these things when there are different configs at play.
When singbox to linux server lookup fails, can you still see the dns requests coming to your Linux server? Or do they never get there?
 

Support SNBForums w/ Amazon

If you'd like to support SNBForums, just use this link and buy anything on Amazon. Thanks!

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top