Thursday, March 28, 2013

Ubuntu with the NetworkManager as a NAT gateway


Sometimes I use my Xubuntu notebook as a NAT gateway for my Windows 7 computer because its WLAN interface works in 5GHz band and Windows computer works only in 2.4GHz. So I connect my Win7 computer to my Xubuntu notebook using a crossover Ethernet cable and turn it ito a NAT gateway using a bash script.

My first script looked very simple:
#!/bin/bash

ifconfig eth0 192.168.10.1 netmask 255.255.255.0 broadcast 192.168.10.255 up

# delete old configuration, if any
# Flush all the rules in filter and nat tables
iptables --flush              
iptables --table nat --flush
          
# delete all chains that are not in default filter and a nat table, if any
iptables --delete-chain     
iptables --table nat --delete-chain

# Set up IP FORWARDing and Masquerading (NAT)
iptables -t nat -A POSTROUTING -o wlan0 -j MASQUERADE
iptables -A FORWARD -i eth0 -j ACCEPT

echo 1 > /proc/sys/net/ipv4/ip_forward

But it didn't really work! The problem was the NetworkManager on the Linux side. NetworkManager is installed by default on all Ubuntu distributions and its derivatives and it is supposed to automate all network related activities. After I run the script and the eth0 interface was up I started Network Connection Diagnostic wizard on Windows side to establish connection (at this time I was also using static IP configuration on Windows) and the NetworkManager on the Linux side re-inited the eth0 interface and my eth0 IP was gone! I didn't want to disable the NetworkManager completely because I would have to bring up the WLAN interface manually by using wpa_supplicant. And I wanted my script to work without additional changes be necessary on both Linux and Windows sides. 

The first thing I needed was to bring up my own DHCP server on the Linux side because I didn't want to keep static IP configuration on the Windows side. As far as dnsmasq was installed by default I tried to start it but port 53 was already occupied by the dnsmasq process! It appeared that NetworkManager starts dnsmasq locally with no cache for automatic DNS queries path resolution since the release of Ubuntu 12.04. Their idea is if a VPN tunnel is used they would redirect all traffic into this tunnel except DNS queries to reduce latency! This solution is too optimistic to my opinion because if I would use a VPN tunnel I would expect that all DNS queries would also be sent through that tunnel and not through another connection silently. Well, at least they added a configuration setting to disable this feature by adding # in the beginning of the “dns=dnsmasq” line of the /etc/NetworkManager/NetworkManager.conf file (read also this post).

Second thing was to add a new network profile to the NetworkManager that I could activate from my script. In the following example I add a new NetworkManager profile called nat_forwarder:

New wired connection profile called nat_forwarder is added

Assigning MAC address of the eth0 device to this profile

Assigning a local IPv4 address to this profile.
After connecting both computers by a crossover cable the NetworkManager will try to activate the default profile 'Wired connection 1' and this should be terminated manually pressing Disconnect in the applet's drop-down menu.

And to activate the NAT gateway now it is only needed to start the following script with root credentials (using sudo):

#!/bin/bash

profile_id=nat_forwarder
dhcp_min=100
dhcp_max=150
out_iface=wlan0

mac_addr=$(nmcli con list id "$profile_id" | sed -nr 's/.*\.mac-address:[^0-9]+(.*)/\1/p')
iface=$(ifconfig | grep -i "$mac_addr" | cut -d\  -f 1)
ifaceip=$(nmcli con list id "$profile_id" | sed -nr 's/^ipv4[^=]*= ([^\/]*).*/\1/p')

[ -z "$ifaceip" -o -z "$mac_addr" ] && {
  echo -e "Error getting data from profile $prifile_id\nmac: $mac_addr\niface: $iface\nifaceip: $ifaceip"
  exit 1
}

subnet=$(echo "$ifaceip"|sed -nr 's/(.*)[^\.]+$/\1/p')

echo -e "mac: $mac_addr\niface: $iface\nifaceip: $ifaceip\nsubnet: $subnet"

killall dnsmasq
dnsmasq -i "$iface" --dhcp-range="$iface,$subnet$dhcp_min,$subnet$dhcp_max,24h"
nmcli con up id "$profile_id"

# delete old configuration, if any
# Flush all the rules in filter and nat tables
iptables --flush              
iptables --table nat --flush
          
# delete all chains that are not in default filter and nat table, if any
iptables --delete-chain     
iptables --table nat --delete-chain

# Set up IP FORWARDing and Masquerading (NAT)
iptables -t nat -A POSTROUTING -o "$out_iface" -j MASQUERADE
iptables -A FORWARD -i "$iface" -j ACCEPT

echo 1 > /proc/sys/net/ipv4/ip_forward

If needed profile_id and out_iface parameters could be changed.

If NAT gateway and interfaces are correctly initialized then it is only needed to start Network Connection Diagnose wizard on the Windows side to establish connection.

No comments: