Posted: Thu May 21, 2009 15:20 Post subject: Assign DNS server address based on MAC address?
As you may already know, Access Restrictions in DD-WRT are rather limited. In fact, the Wiki entry for this topic states "For more advanced content filtering try OpenDNS". I took a look at what OpenDNS has to offer and it looks good enough to keep my under-age kids from seeing most stuff that they really aren't ready to deal with. Unfortunately, OpenDNS can only see the public IP address on my modem, so any limits I place on my kids will also be placed on me...
So, I'd like to be able to refer certain MAC addresses on my home network to OpenDNS, but have other MAC addresses use DNS from my ISP. (And yes, I do know that MAC addresses are easily spoofed on PCs, but the particular devices I'm concerned with are iPod Touch and Nintendo DSi).
Any ideas on how to specify DNS servers based on client MAC address?
Easiest is giving those PC's a fixed DNS to OpenDNS.
You yourself will be using the router's (ISP) DNS.
There are many more options, but if this does the job I would go for this one.
SNR wrote:
Several dozen Views of this post but no replies yet. Bumping this up for possible assistance from the midnight crowd...
I was working... Your post is of this morning. _________________ Asus RT16N + OTRW
Kingston 4GB USB-disk 128 MB swap + 1.4GB ext3 on /opt + 2 GB ext3 on /mnt
Copperjet 1616 modem in ZipB-config
Asterisk, pixelserv & Pound running on router
Another Asus RT16N as WDS-bridge
Why not set up two routers, one with your needs and the other for the kids? and just connect both to your cable modem router?
At this point I only have my one little old WRT54GL and I've been able to make do with it so far (and I enjoy the challenge in these circumstances). :)
... IF I had two routers, it's not clear to me how to connect them both to a single cable (or DSL) modem (unless I daisy-chain one into the other, which I think would defeat the purpose of having two routers).
Easiest is giving those PC's a fixed DNS to OpenDNS.
You yourself will be using the router's (ISP) DNS.
There are many more options, but if this does the job I would go for this one.
[...]
I was working... Your post is of this morning.
Hello frater! No problem with your work schedule, I didn't expect you to be the only one to come to my rescue, LOL. :oops:
If at all possible I'd like to avoid making any tweaks to the config on my kids' handheld devices, because there's no way for me to guarantee that they will keep them that way. This is also why I decided against installing browser replacement apps (e.g. Mobicip on the iPod Touch). It's just too easy for anyone with one of these things in their hands to take total control of it, no matter what I might do to it.
So I decided to just keep the default settings on the devices (which uses DHCP), and accommodate that fact in the router and OpenDNS. I found the OpenDNS Wiki page page which also gives instructions on how to setup DNS-O-Matic, and I've got that all working now.
The Wiki page includes a section named "Intercept DNS Port" that shows how to force LAN clients to use OpenDNS instead of the WAN settings on the Setup page. Here's the Firewall code from that section:
Code:
iptables -t nat -A PREROUTING -p udp -i br0 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
iptables -t nat -A PREROUTING -p tcp -i br0 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
I think I can hack around here to make the $(command) instead get the current IP addresses for the clients I'd like to filter, based on the name of the interface that they are restricted to (br1 in this case). A better (more general) solution would be to iterate the list of clients that are targets for Access Restrictions (as defined on that page of the GUI). However, as I noted above, I'm using MAC addresses to target these clients, and at the moment I haven't had enough sleep for the solution to gel in my brain.
I'm gonna take a nap during lunchtime here. Maybe by the time I get back you will have the code ready for me.
The Wiki page includes a section named "Intercept DNS Port" that shows how to force LAN clients to use OpenDNS instead of the WAN settings on the Setup page. Here's the Firewall code from that section:
Code:
iptables -t nat -A PREROUTING -p udp -i br0 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
iptables -t nat -A PREROUTING -p tcp -i br0 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
I think I can hack around here to make the $(command) instead get the current IP addresses for the clients I'd like to filter, based on the name of the interface that they are restricted to (br1 in this case). A better (more general) solution would be to iterate the list of clients that are targets for Access Restrictions (as defined on that page of the GUI). However, as I noted above, I'm using MAC addresses to target these clients, and at the moment I haven't had enough sleep for the solution to gel in my brain.
Oops, sorry, I misinterpreted that code....
The $(nvram get lan_ipaddr) command is the relay for DNS requests, not the source of those requests. I think in my case, I don't want to specify the router address, but instead I want to use one of the OpenDNS addresses, correct? Is there any way to specify both addresses, for failover purposes?
It's the -i br0 portion of the CL that I'd like to modify to instead handle filtered MAC addresses directly (if iptables can accept this). Otherwise I will need to parse nvram output to get the current IP address associated with the MAC.
You can also do it the other way around.
You yourself can use static DNS to your ISP's DNS-server..
I think it's also possible to configure dnsmasq so they will get another dns-entry.
The "Intercept port" is made as an extra when they try to use a static DNS and still force them to the lan ip of the router.
Change your dynamic pool to go from 192.168.1.128 and up, they will then be forced to use 192.168.1.1 as the DNS-server which is configured to use opendns...
Code:
iptables -t nat -A PREROUTING -p udp -i br0 -s 192.168.1.128/25 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
iptables -t nat -A PREROUTING -p tcp -i br0 -s 192.168.1.128/25 --dport 53 -j DNAT --to $(nvram get lan_ipaddr)
Even better.....
Configure a transparent proxy on your LAN on 192.168.1.20 and let that machine use opendns.
Use the transparent proxy script... and exclude 192.168.1.0/25 (the lower half)
If you want free access, you should give the machine an IP in the lower half and the one to use the proxy should get an IP in the upper half.
Code:
_NW=192.168.1.1/24
ROUTER_IP=`nvram get lan_ipaddr`
PROXY=192.168.1.20
EXCLUDE=192.168.1.0/25
PPORT=3128
_________________ Asus RT16N + OTRW
Kingston 4GB USB-disk 128 MB swap + 1.4GB ext3 on /opt + 2 GB ext3 on /mnt
Copperjet 1616 modem in ZipB-config
Asterisk, pixelserv & Pound running on router
Another Asus RT16N as WDS-bridge
you should know me by now...the more time I can spend to make things "simpler", the better.
frater wrote:
[...]
Even better.....
Configure a transparent proxy on your LAN on 192.168.1.20 and let that machine use opendns.
[...]
I'd prefer to avoid setting up another PC for this purpose.
I have some more questions about your first suggestion but I haven't had that nap yet. I will post some questions later if I can't get it figured out myself. Thanks...
OK, after getting a bit of sleep I woke up with a solution in my mind that seems to be easiest for my situation. A quick rundown of that situation (which is probably similar to many noob DD-WRT parents):
- DHCP from my ISP
- PPPoE on modem
- DD-WRT on WRT54GL
- Physical interface wl0 using WPA2/AES for laptop PCs
- Virtual interface wl0.1 using WEP for handheld devices
- MAC filtering on both interfaces
- My kids are the only ones using handheld devices
- I want to implement content filtering for my kid's handhelds
OpenDNS can only apply filters to DNS requests from known IP addresses. Since I've got DHCP from my ISP, I must send DDNS updates to OpenDNS when my ISP-provided address changes. As I mentioned earlier in this thread, I've got DDNS setup and working in DD-WRT per the OpenDns with DNS-O-Matic section of the OpenDNS Wiki page.
However, I didn't follow the Basic Setup instructions on the Wiki page (i.e. entering OpenDNS server addresses in the Setup tab), because I don't want to restrict all of my household to the OpenDNS filters. Instead, I tweaked the Firewall rules listed in the Intercept DNS Port section of the page, to force all clients on br1 (linked to wl1.0, for handhelds) to use the OpenDNS servers for all DNS requests, like this:
Code:
# Force use of OpenDNS for clients on second bridge
opendns1=208.67.222.222
opendns2=208.67.220.220
iptables -t nat -A PREROUTING -p udp -i br1 --dport 53 -j DNAT --to $opendns1 --to $opendns2
iptables -t nat -A PREROUTING -p tcp -i br1 --dport 53 -j DNAT --to $opendns1 --to $opendns2
In the Access Restrictions page of DD-WRT I've also implemented a Deny policy for early morning, another Deny policy for late evening, and a Filter policy for the remaining hours to Catch all P2P Protocols. These policies are all tied to the MAC addresses of the handhelds (this allows me to use the default DHCP config for the networking profiles on the devices).
So I'm using DD-WRT to enforce hourly restrictions and prohibit the use of P2P, and to also force the use of OpenDNS content filtering, but only on handheld devices. This all seems to be working as expected. Hopefully this info will help out some of you.
I still have some questions about the Firewall code that I tweaked. I'm gonna ask them later in a follow-up post, and hopefully some of you gurus can enlighten me...
If this is working, it's quite easy to have these rule work for a limited IP-range by adding
Code:
-s 192.168.1.128/25
to each firewall rule.
Now you only have to assign IP's to the upper half of your /24 subnet to invoke it.
That's quite easy to accomplish using reserved addresses.. _________________ Asus RT16N + OTRW
Kingston 4GB USB-disk 128 MB swap + 1.4GB ext3 on /opt + 2 GB ext3 on /mnt
Copperjet 1616 modem in ZipB-config
Asterisk, pixelserv & Pound running on router
Another Asus RT16N as WDS-bridge
If this is working, it's quite easy to have these rule work for a limited IP-range by adding
Code:
-s 192.168.1.128/25
to each firewall rule.
Now you only have to assign IP's to the upper half of your /24 subnet to invoke it.
That's quite easy to accomplish using reserved addresses..
If I didn't already have a second dedicated AP for the handhelds, then yes, splitting the range like you suggest would probably be easier. But I would have to manually assign IPs to the handhelds to force them to use the content filtering, correct? Again, there isn't much I can do to ensure that settings on the handhelds aren't changed.
FYI, the second AP was previously created because some of the handhelds don't do WPA2 very well. In particular the Nintendo DSi requires configuration via AOSS or WPS which AFAIK are not supported by DD-WRT. I didn't want to downgrade my entire WLAN to WEP just to accommodate the handhelds, so I spent a few days here learning how to setup a second AP for WEP. When I later realized that I should enforce access restrictions on the handhelds, they were already segregated into the dedicated WLAN, so I didn't need to do anything else to the clients or the router to manage them as a group.
Looking at my notes again, here's a review of how to do it the way I did. This assumes that you already have a dedicated AP for the clients that you want to restrict:
- Sign up for OpenDNS
- Setup appropriate content filtering in OpenDNS
- Configure DNS-O-Matic to update OpenDNS
- Configure DDNS in the router to update DNS-O-Matic
- Add a Firewall rule to force clients on the restricted AP to use OpenDNS
- Create Policies as needed to enforce Access Restrictions based on the MAC addresses of the handhelds:
- Deny Internet access during early morning and late evening
- Filter Internet access during the remaining hours:
- Catch all P2P protocols
- Block other services as desired (IRC, etc.)
If this is working, it's quite easy to have these rule work for a limited IP-range by adding
Code:
-s 192.168.1.128/25
to each firewall rule.
Now you only have to assign IP's to the upper half of your /24 subnet to invoke it.
That's quite easy to accomplish using reserved addresses..
Sorry, I didn't really notice that last part of your reply. Yes, in a single AP scenario I could use DHCP reservations to force certain clients to always receive addresses in a specific range. But that makes configuring DHCP a bit more complicated, and I always try to keep things as simple as possible. :wink:
And in my case, with each AP using its own address range, it's just easier to assign the OpenDNS addresses based on the WLAN (i.e. br1 vs. br0) rather than the address range. But I could do either with only a tweak to the iptables command (as you suggested) and not need to change anything else.
A few comments/questions about the code below (which I lifted from the OpenDNS Wiki page and then tweaked for my purposes). Can someone please answer these Qs?
Code:
# Force use of OpenDNS for clients on second bridge
opendns1=208.67.222.222
opendns2=208.67.220.220
iptables -t nat -A PREROUTING -p udp -i br1 --dport 53 -j DNAT --to $opendns1 --to $opendns2
iptables -t nat -A PREROUTING -p tcp -i br1 --dport 53 -j DNAT --to $opendns1 --to $opendns2
1. Per the iptables manpage here, the DNAT target extension supports multiple --to options for round-robin load balancing in kernels up to 2.6.10. DD-WRT is still running a 2.4 kernel, correct?
2. The manpage shows that the option should actually be --to-destination so why/how does the shorter form --to work? Am I not reading the manpage correctly? Or is DD-WRT using an older version of iptables?
3. Why is the -A command used to Append these rules to the chain? Shouldn't the -I command be used to Insert the rules at the top of the chain? Shouldn't these new rules be inserted at the top of the chain, in case conflicting rules are already present?
1. Per the iptables manpage here, the DNAT target extension supports multiple --to options for round-robin load balancing in kernels up to 2.6.10. DD-WRT is still running a 2.4 kernel, correct?
I finally remembered how to get the kernel version and yes, the very latest build as of this writing (12250) is still using v2.4:
root@DD-WRT:~# cat /proc/kmsg
<0>CPU ProcId is: 0x00029008, options: 0x0000004d
<0>Linux version 2.4.37 (eko@dd-wrt) (gcc version 3.4.6 (OpenWrt-2.0)) #3759 Tue Jun 2 11:06:20 CEST 2009
(The Linux Inside Wiki page states otherwise but is apparently in error.)