Millet Porridge

English version of https://corvo.myseu.cn

0%

Simulating Router Functions with virtualbox and Implementing Ad Filtering

Last weekend I went to Shenzhen to play and happened to see my friend’s router; he told me it’s a soft router. Domestic websites can go through domestic lines, foreign websites through foreign lines. At home this weekend I happened to have time to research router functions. I know what readers want to hear, but I don’t plan to cover it. You can use my approach to build a simulated router with virtualbox for simulation and debugging.

This blog mainly wants to introduce implementing router functions in a virtual machine, plus a scheme for home-router ad filtering.

Using the OpenWRT system would make things much easier, and the whole process would be idiot-simple, because everyone has prepared the solutions for you. So the virtual machine used here is Ubuntu server; once you’re used to Linux, any system works. Tinkering with routers was a high-school dream of mine — I find it fairly interesting, though it’s nothing new.

Network Structure

The network structure is as follows:

Creating the Virtual Machines

We need to create two virtual machines: one as the router, the other as an ordinary computer. They can be created cleverly.

First you need at least one Ubuntu machine; then right-click to clone it, immediately adding a new virtual machine. You can also try the snapshot feature.

NIC Configuration

The router needs two NICs

The first for accessing the external network:

The second provides the routing function:

![][4]

For the ordinary computer

Only one NIC is needed:

![][5]

Note this NIC needs dhcp disabled; the concrete configuration is: Management => Host Network Manager => uncheck the dhcp feature

![][6]

Implementing Router Functions

When we normally use a router to access the internet, the router itself generally has IP 192.168.1.1, then assigns us IP 192.168.1.xxx via the dhcp protocol. So in the router we need: 1. fix the NIC’s IP address, 2. establish a dhcp service.

Fixing the NIC IP Address

Newer Ubuntu versions use the netplan tool; the config file is:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@UbuntuRoute:/home/corvo# cat /etc/netplan/00-installer-config.yaml 
# This is the network config written by 'subiquity'
network:
ethernets:
enp0s3:
dhcp4: true
enp0s8:
dhcp4: false
addresses: [192.168.59.1/24]
gateway4: 192.168.101.65
nameservers:
addresses: [8.8.8.8,8.8.4.4]
version: 2

Here enp0s3 is the NIC the router uses to access external websites; enp0s8 is the NIC connected to the subnet.

Establishing the dhcp Server

In Ubuntu, you can install the isc-dhcp-server server tool and modify the following configuration, indicating the dhcp server works for the enp0s8 NIC.

1
2
3
root@UbuntuRoute:/home/corvo# tail -2 /etc/default/isc-dhcp-server
INTERFACESv4="enp0s8"
INTERFACESv6=""

Then you need to specify the network segment dhcp can allocate:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@UbuntuRoute:/home/corvo# tail -8 /etc/dhcp/dhcpd.conf
subnet 192.168.59.0 netmask 255.255.255.0 {
option routers 192.168.59.1;
# be careful not to fill in the subnet mask wrong — the /24 above means the mask is 255.255.255.0
option subnet-mask 255.255.255.0;

# specify the dns server
option domain-name-servers 114.114.114.114;

# the segment dhcp can allocate: the 100~200 range
range 192.168.59.100 192.168.59.200;
}

# start the dhcp server
root@UbuntuRoute:/home/corvo# systemctl start isc-dhcp-server.service

Confirming the Ordinary Computer’s Connection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
corvo@UbuntuClient:~$ ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 08:00:27:2d:f9:1e brd ff:ff:ff:ff:ff:ff
inet 192.168.59.100/24 brd 192.168.59.255 scope global dynamic enp0s3
valid_lft 499sec preferred_lft 499sec

# view the current dns server
corvo@UbuntuClient:~$ resolvectl status | tail -3
DNSSEC supported: no
Current DNS Server: 114.114.114.114
DNS Servers: 114.114.114.114

Adding Packet Forwarding to the Router

Our computer has now obtained an ip address; the next step is internet access, mainly two steps, both performed on the router:

1
2
3
4
5
6
# allow the kernel to forward packets between NICs
UbuntuRoute# echo "net.ipv4.ip_forward = 1" >> /etc/sysctl.conf
UbuntuRoute# sysctl -p

# forward all nat traffic to the enp0s3 NIC
UbuntuRoute# iptables -t nat -A POSTROUTING -o enp0s3 -j MASQUERADE

Next you can try browsing the internet on the ordinary computer:

1
2
corvo@UbuntuClient:~$ curl ip.sb
113.67.xx.xxx

Building an Internal DNS Server and Ad Filtering

My earlier blog already introduced the DNS service: https://corvo.fun/2018/07/30/a-discussion-on-dns-queries/

Establishing the dns Server

In the example above we were lazy with the dns server, using 114.114.114.114; of course you can also build your own dns service — generally using dnsmasq.

1
2
3
4
5
6
# install dnsmasq
> apt install dnsmasq
# stop the original local resolution service
> systemctl stop systemd-resolved.service
# start dnsmasq
> systemctl start dnsmasq

At this point you should be unable to access any website, because the dnsmasq service isn’t configured yet. I added the upstream dns server in the config file, then restarted dnsmasq.

1
2
UbuntuRoute# tail -3 /etc/dnsmasq.conf
server=114.114.114.114

Modifying the dns Server Target

Since we used a dhcp server, the part to modify is the dhcp server’s configuration; after modifying, the dhcp service needs restarting:

1
2
3
4
5
6
7
8
9
10
11
12
root@UbuntuRoute:/home/corvo# tail -8 /etc/dhcp/dhcpd.conf
subnet 192.168.59.0 netmask 255.255.255.0 {
option routers 192.168.59.1;
# be careful not to fill in the subnet mask wrong — the /24 above means the mask is 255.255.255.0
option subnet-mask 255.255.255.0;

# specify the dns server — note, here it becomes the router's IP
option domain-name-servers 192.168.59.1;

# the segment dhcp can allocate: the 100~200 range
range 192.168.59.100 192.168.59.200;
}

Wait a few minutes, or restart that user computer, and you’ll find its dns address has changed:

1
2
3
4
corvo@UbuntuClient:~$ resolvectl status  | tail -3
DNSSEC supported: no
Current DNS Server: 192.168.59.1
DNS Servers: 192.168.59.1

One Implementation of Ad Filtering

Some approaches I’ve encountered are implemented via dns hijacking — e.g. this blacklist, recording the domains of advertising and analytics sites; using dnsmasq, their domains are returned as 0.0.0.0:

1
2
3
4
5
6
wget -O /etc/dnsmasq.d/notracking.conf https://raw.githubusercontent.com/notracking/hosts-blocklists/master/dnsmasq/dnsmasq.blacklist.txt

# the contents are statements like this
> address=/00-gov.cn/#
> address=/000-hidro-1.info/#
> address=/000359.xyz/#

Then turn on dnsmasq’s include feature, adding conf-dir=/etc/dnsmasq.d/,*.conf. Afterwards restarting dnsmasq achieves the desired effect, e.g.:

1
2
3
4
5
6
7
# effect on the router
UbuntuRoute# dig +short 000-hidro-1.info
0.0.0.0

# effect on the user computer
corvo@UbuntuClient:~$ dig +short 000-hidro-1.info
0.0.0.0

The ad filtering function is basically implemented.

Summary

I mainly wanted to introduce the router’s simple implementation principle, and along the way introduce building and using an internal dns server. Knowing only these should be insufficient for your purposes; I suggest learning more about iptables — you can easily implement all kinds of traffic-splitting effects. Of course, you also need to master dnsmasq.

[4]: https://rawforcorvofeng.cn/Snipaste_2020-12-06_22-04-33.png [5]: https://rawforcorvofeng.cn/Snipaste_2020-12-06_22-05-57.png [6]: https://rawforcorvofeng.cn/Snipaste_2020-12-06_22-07-45.png