Probably, any of you even remotely knows what routing is. So, routing is, however banal it may sound, there is a choice of route. In this article, under this term, I will understand the choice of the route following a network IP packet. The fact is that modern software routers (and I’ll be just talking about one of the representatives of this class of devices) can only fully work with the ip protocol.

Why did I decide to describe the construction of the router based on the GNU / Linux OS? There are two main reasons:

  • the GNU / Linux kernel can fit on a floppy disk, which can allow you to create a very functional router regardless of the specific machine, besides, you can “revive” old machines and make them work for the benefit of people;
  • The Linux kernel (2.4, 2.2) supports very useful routing functions, and can be specially tailored for use as a router, besides, the standard Linux 2.4 firewall – iptables – can “mark” (do not think anything bad) certain packets, and the kernel can perform route selection according to these tags.

This opens up opportunities for creating networks with a complex structure. Another very important feature is the versatility of GNU / Linux – in my opinion, this OS supports all common network protocols to one degree or another. Another important feature is the free of charge of the entire routing system. From the point of view of many administrators, a router is simply a black box that receives and transmits packets, but proper routing configuration is a guarantee of the effectiveness and often the security of the entire network. It is very interesting to use routing to distribute the load, transfer specific traffic to a specific host (for analysis), and reduce the risk of DoS attacks. Routing can limit network “storms” and significantly increase network bandwidth.

Routing is static and dynamic. The difference is that with static routing, all packet transfer rules are statically defined and can only be changed manually, dynamic routing is applied when there are several routers in the network, and finding the path to a remote host becomes a nontrivial task. Dynamic routing is more suitable for frequently changing networks with a complex structure. Although GNU / Linux supports both types of routing, but in this article I will talk about static routing using the iproute2 package, by the way, written by our programmer Alexei Kuznetsov. To get started, you must configure the kernel accordingly and install the iproute package. I will stop on adjustment of a kernel. In the kernel, you must enable a number of routing options (I think There is no need to explain how to configure and compile the kernel). I assume that you are configuring the kernel with the command “make menuconfig”.

On the Networking Options page you need to enable the following items:

  • IP: advanced router – enable advanced routing capabilities;
  • IP: policy routing — routing for some internal packet fields (usually used in conjunction with a firewall), as well as for advanced routing capabilities, such as routing according to source-based routing address;
  • IP: use netfilter MARK value as routing key – enable routing according to packet marking with a firewall;
  • IP: use TOS value as routing key – packet based routing service type (TOS), helps to increase network bandwidth in the presence of multiple packet paths;
  • IP: large routing tables — enable large (> 64 rules) kernel routing tables.

You can also enable tunnel support, but I will not linger on it. After configuring the kernel, you need to install iproute2. In most GNU / Linux distributions, this program is included in the distribution, for example, for Debian GNU / Linux, the command will look like this:

# apt-get install iproute

The compilation is standard, but there is no install target in the Makefile – you need to copy binary files from the ip directory ( cp ifcfg ip routef routel rtacct rtmon rtpr / sbin ) and from the tc directory ( cp tc / sbin ) to / sbin, and ./etc/iproute2/ – in / etc / iproute2 /.

Also do not be lazy to download the Linux Advanced Routing and Traffic Control HOWTO, which can be found at . In fact, this tutorial is simply necessary to configure complex static routing based on Linux. I myself set up network routing based on this guide, so if this article did not solve your problem, it’s better to refer to this document.

The iproute package consists of actually two traffic management utilities:

  • ip – routing management;
  • tc – routing queue management.

First, I’ll talk about the general principles of the ip command, the command syntax is:

ip [options] {route object} {command or HELP}

From the options the most useful is the choice of the IP family:

  • –4  – IPv4;
  • –6  – IPv6.

Routing objects are represented by the following list:

  • link – network device (real physical or virtual, for example, vlan or tunnel);
  • address – device ip-address;
  • neighbor – ARP cache;
  • route – routing tables;
  • rule – routing rules;
  • maddress – broadcast address;
  • mroute – broadcast routing tables;
  • tunnel — The IP tunnel.

Commands for different objects are different, but for all objects there is a standard set of commands: add (add), delete (delete) and show (show; you can also apply a list or ls). The syntax of different commands for different objects can be completely different, so I will not describe here all the commands of each object. I will stick with Linux Adv. Routing HOWTO and give some useful examples of using the ip command. First, let’s review the network devices present on our test machine (let it have ip-addresses and

# ip link list
1: lo:  mtu 16436 qdisc noqueue
    link / loopback 00: 00: 00: 00: 00: 00 brd 00: 00: 00: 00: 00: 00
2: dummy0:  mtu 1500 qdisc noop
    link / ether 00: 00: 00: 00: 00: 00 brd ff: ff: ff: ff: ff: ff
3: eth0:  mtu 1500 qdisc pfifo_fast qlen 10
    link / ether 48: 54: e8: 01: ef: 56 brd ff: ff: ff: ff: ff: ff
4: eth1:  mtu 1500 qdisc pfifo_fast qlen 10
    link / ether 00: e0: 4c: 39: ef: 56 brd ff: ff: ff: ff: ff: ff

Now it is time to proceed to the consideration of the simplest case of the organization of routing. For example, in a large local network there are three computers that are supposed to have access to the global network. At the same time there are two connections with the provider: fast ADSL and slow modem. It is desirable to send one computer (with the address to the global network via a modem, and the other two (with the addresses and 192.168.21) via ADSL. Traffic sent to the outside world from other computers should be redirected to the sniffer located at, and the sniffer can also be located on this computer ( tcpdump -i ethX ).

View network cards on the server; the list will be something like this:

# ip link list
1: lo:  mtu 16436 qdisc noqueue
    link / loopback 00: 00: 00: 00: 00: 00 brd 00: 00: 00: 00: 00: 00
2: eth0:  mtu 1500 qdisc pfifo_fast qlen 10
    link / ether 48: 54: e8: 01: ef: 56 brd ff: ff: ff: ff: ff: ff
    inet brd scope global eth0
3764: ppp0:  mtu 1492 qdisc pfifo_fast qlen
    link / ppp
    inet peer scope global ppp0
3765: ppp1:  mtu 1492 qdisc pfifo_fast qlen
    link / ppp
    inet peer scope global ppp1

Obviously, ppp0 corresponds to a modem connection, and ppp1 corresponds to an ADSL connection. Let’s look at the routing tables (here all the kernel routing tables are displayed, the kernel decides whether a particular table is used based on the source address of the packet, the route utility is only able to operate on the main and local tables, iproute2 allows you to create your own tables, which will be described later ):

# ip rule list
0: from all lookup local
32766: from all lookup main
32767: from all lookup default

As you can see, as long as our tables apply to all packages. Add a new table for machines connected to the Internet via ADSL:

# echo 200 inet_adsl >> / etc / iproute2 / rt_tables

This command requires some explanation: the number 200 is chosen arbitrarily, the main thing is that it does not coincide with other routing table numbers, the name inet_adsl is also given arbitrarily, but then this table can be managed by name, so in your own interest give a clear name to the table facilitate the process of further customization.

Add the packet acceptance rules to the table:

# ip rule add from table inet_adsl
# ip rule add from table inet_adsl

These commands, I think, are understandable, so we immediately look at our routing tables:

# ip rule list
0: from all lookup local
32764: from lookup inet_adsl
32765: from lookup inet_adsl
32766: from all lookup main
32767: from all lookup default

Now you need to add a default route guide for the inet_adsl table – then all packets from the required machines will be sent to the specified gateway:

# ip route add default via dev ppp1 table inet_adsl

After that, you need to reset the router’s cache:

# ip route flush cache

Now turn to set up a dial-up connection. I think the following commands should not cause difficulties:

# echo 201 inet_modem >> / etc / iproute2 / rt_tables
# ip rule add from table inet_modem
# ip route add default via dev ppp0 table inet_modem
# ip route flush cache

To view the routing tables, you can use the following command:

# ip route list [table table_name]

Now you need to enable sniffer to track packets that came from the local network. Add a virtual network card:

# ifconfig eth0: 1 up

And we will configure the routing rules so that the packets from the local network directed to the external network are directed to the address, i.e. so that the administrator can watch for attempts to access the external network. This problem is not as trivial as the previous one, but a solution does exist. The problem is solved by integrating the capabilities of netfilter (iptables) and iproute2. Inside the kernel, it is possible to install tags on the packets (tags set iptables, but note that these tags exist only within the kernel, and do not go beyond the boundaries of this computer). A detailed description of the netfilter system is beyond the scope of this article, so I will limit the installation tags on a specific example:

# iptables -A PREROUTING -i eth0 -s -d!
           -t mangle -j MARK --set-mark 2

Some comments: pay attention to the -j MARK and –set-mark flags  – the last flag can set a label from 1 to 255. After setting the iptables rule, you need to return to the iproute2 setting again. Note that now all the packages we need are labeled 2, it remains only to send all such packages to the sniffer located at

# echo 202 sniffing >> / etc / iproute2 / rt_tables
# ip rule add fwmark 2 table sniffing

Notice that this line fetches the packets according to their label:

# ip route add default via dev eth0: 1 table sniffing
# ip route flush cache

Run the sniffer itself (in the background):

# tcpdump -i eth0: 1> /var/log/tcpdump.log &

At the same time, you need to take care of the correct installation of permissions to access the dump file, set the correct umask or set the attributes manually:

# touch /var/log/tcpdump.log
# chattr 600 /var/log/tcpdump.log

To enhance security, you can also run a sniffer via chroot ( chroot / var / log tcpdump -i eth0: 1 ), but this is usually done in an initialization script.

There are several other nuances in this example, namely: the installation of network options for the kernel. Kernel options are usually set using the / proc file system: entering the necessary values ​​into specific files. For us, it is necessary to disable icmp redirect responses so that our router does not inform clients about the choice of the required route directly (this will deprive us of the possibility of tagging packets, and, moreover, it is not understood by all clients by default). To do this, do the following:

# echo 0> / proc / sys / net / ipv4 / conf / all / send_redirects
# echo 0> / proc / sys / net / ipv4 / conf / default / send_redirects
# echo 0> / proc / sys / net / ipv4 / conf / eth0 / send_redirects

Do not forget also about the correct configuration of the firewall, and if there are several subnets, it is advisable to make sure that the direct transfer of packets from the subnet to the subnet is turned off (that is, if the packet is sent to another subnet, it should not be transmitted to another network interface without processing ):

# echo 0> / proc / sys / net / ipv4 / ip_forward

The only serious disadvantage of the above scheme is the possibility of replacing the ip-address. Unfortunately, this deficiency cannot be corrected, but you can additionally track calls to the external network. This concludes the description of this “simple” task for the administrator and proceed to the description of the installation of IP-tunnels.

In general, any network tunnel encapsulates packets (in fact, the necessary header is added to each packet). Tunnels allow you to organize communication of several subnets with one connection. The Linux kernel integrates support for several types of IP tunnels. Tunnel management is done through the ip tunnel command . But first you need to turn on support for tunnels in the kernel. On the page “Networking options” note the following options:

  • IP: tunneling – kernel support for tunnels;
  • IP: GRE tunnels over ip – support for GRE tunnels that have the ability to encapsulate ipv6 traffic, moreover, GRE is the de facto standard in Cisco routers, so use a GRE tunnel to create a tunnel between a Linux machine and a Cisco router.

Imagine organizing a tunnel between two computers and connecting two subnets. To add a GRE tunnel, you can use the following commands: on server

# ip tunnel add tuna mode gre remote local ttl 255

This command sets the GRE tunnel from the machine to the machine, use the sit (mode sit) type to create a pure IPV6 tunnel, and you must manually add the IPV6 address to the tunnel ( ip –6 addr add ipv6_addr dev tunsit ). Note that you can add a tunnel with any name consisting of letters and numbers. The ttl field is optional, but each packet passing through the tunnel will be assigned a given ttl. The second step in configuring the tunnel is to configure routing through this tunnel: we enable the virtual network interface created by the previous command:

# ip link set tuna up

Now you need to assign the ip-address to the created tunnel:

# ip addr add dev tuna

Add a route to the network through the created tunnel:

# ip route add dev tuna

The last action can be performed using the old route utility ( route add-net netmask dev tuna ), but the iproute IMHO syntax is somewhat simpler. At the other end of the tunnel ( we perform similar actions:

# ip tunnel add tunb mode gre remote local ttl 255
# ip link set tunb up
# ip addr add dev tunb
# ip route add dev tunb

After that, the tunnel begins to function. Also note that an additional header of 20 bytes is added to the data passing through the tunnel, so the MTU for the tunnel is not 1500, but 1480 bytes. To solve this problem, we slightly modify the command for adding a route, specifying mtu:

# ip route add dev tuna mtu 1480

Explicit indication of mtu is a very useful thing in many cases, for example, when organizing a VLAN (IEE802.1q) it is also necessary to reduce the interface MTU value.

If you plan to organize a tunnel with a CISCO router, then its configuration may look like this:

interface Tunnel1
description IP tunnel
no ip address
no ip directed-broadcast
ip address
tunnel source Serial0
tunnel destination
tunnel mode ipip
ip route Tunnel1