Sunday, March 12, 2017

Notes for iproute2, network namespace, and iptables NAT

Some random notes for stuff. Have fun!

# the ip command line tool (iproute2)

# setup an $INTERFACE and bind to $IP/$MASK
# ip link set $INTERFACE up
# ip addr add  $IP/$MASK dev $INTERFACE
# ip route add $IP/$MASK dev $INTERFACE

# delete the above settings
# ip route del $IP/$MASK dev $INTERFACE
# ip addr del $IP/$MASK dev $INTERFACE
# ip link set $INTERFACE down

# static routing
# ip route add default via $GATEWAY dev $INTERFACE
# ip route add $IP dev $INTERFACE

# search devices name
$ ls /sys/class/net/
$ ip link

# flush everything!
# ip addr flush dev $INTERFACE
# ip route flush dev $INTERFACE
# ip link set $INTERFACE down

# evil stuff

# promiscuous mode
# ip link set dev $INTERFACE promisc on

# MAC address spoofing
# ip link set dev $INTERFACE down
# ip link set dev $INTERFACE address XX:XX:XX:XX:XX:XX
# ip link set dev $INTERFACE up

# network namespace (need root permission)

# add and delete the network namespace
# ip netns add $NS_NAME
# ip netns del $NS_NAME

# ip -n shortcut
# ip -n $NS_NAME [ OPTIONS ] OBJECT { COMMAND | help }
# ip netns exec $NS_NAME ip [ OPTIONS ] OBJECT { COMMAND | help }

# run an app under $NS_NAME (remember to downgrade permission)
# ip netns exec $NS_NAME sudo -u $REGULAR_USER $application

# in scripts ...
NS_EXEC="ip netns exec $NS_NAME"

# virtual ethernet interface (create vpn0 outside and peer vpn1 under $NS_NAME)
# ip link add vpn0 type veth peer name vpn1
# ip link set vpn0 up
# ip link set vpn1 netns $NS_NAME up

# finding apps under $NS_NAME, and kill them all!
# ip netns pids $NS_NAME
# ip netns pids $NS_NAME | xargs -n1 -I{} ps -q {} -o pid=,comm=
# ip netns pids $NS_NAME | xargs kill

# sysctl settings to enable forwarding
#   save to /etc/sysctl.conf or /etc/sysctl.d/30-ipforward.conf
# sysctl net.ipv4.ip_forward=1
# sysctl net.ipv6.conf.default.forwarding=1
# sysctl net.ipv6.conf.all.forwarding=1

# iptables stuff

# allow a $PORT from $IP/$MASK for tcp/udp
#   drop: -j DROP
# iptables -A INPUT -p tcp --dport $PORT -s $IP/$MASK -j ACCEPT
# iptables -A INPUT -p udp --dport $PORT -s $IP/$MASK -j ACCEPT

# IP masquerade for NAT
#   -o output interface
#   -s source $IP/$MASK

# DNAT on all protocols from $IP1 to $IP2
#  -d (original) destination IP
#  --to-destination destination IP behind NAT
# iptables -t nat -A PREROUTING -d $IP1 -j DNAT --to-destination $IP2

# specify only tcp/$PORT
#   -p protocol, usually tcp, udp, icmp, icmpv6, or all
#   --to-destination could be a range [ipaddr[-ipaddr]][:port[-port]], remain the same port if not specified
# iptables -t nat -A PREROUTING -p tcp -d $IP1 --dport $PORT -j DNAT --to-destination $IP2

# use MATCH extension, see iptables-extensions(8)
#   Example:
# iptables -t nat -A PREROUTING -i $INTERFACE -p tcp -m tcp --dport $PORT1 -j DNAT --to-destination $IP:$PORT2

# save and restore
# iptables-save
# iptables-restore

# dump current rules
#   -n no DNS lookup
#   -v verbose
#   -L list
#   -t table (default: filter)
#   --line-numbers might be helpful

# iptables -nvL
# iptables -nvL -t nat

# Reference:

ip(8), ip-address(8), ip-link(8), ip-netns(8), ip-route(8)

Friday, March 10, 2017

Running a service when your ISP doesn't like you

We are running out of IPv4.

It is more common that ISPs won't give you a public IP nowadays. Especially if you live in an apartment, they only give you a DHCP port usually. This is a bit inconvenient (or annoying?) for people who want to run services, which requires a public IP.

Here's a common solution:

1. Rent a VPN on DigitalOcean ($10/mo)
2. Connect my desktop with my VPN
3. Run the server on my desktop
4. Forward traffic from my VPN to my desktop

The issue here is that OpenVPN will take over the entire interface (all the traffic will route through the tun0 device). My solution to that is jailing OpenVPN under a Linux network namespace.

Recently I modified other's script to run different kinds of VPNs under a LInux network namespace:

With the help of this script, I can just simply use iptables to perform a port forwarding on my VPS's public interface to the private IP of my desktop.

The overview of the design would be like this:

| VPS public IP (eth0 / x.x.x.x)
| openVPN (tun0 /
| ---------------------------------------------------------------
| sudo iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 1234 -j DNAT --to
| sysctl net.ipv4.ip_forward=1
| my ISP ( under NAT ... orz)
| Desktop interface (enp0s0 / 192.168.a.b)
| Linux network NS (vpn0 /
| ip netns exec  ip route add default via dev vpn1
| iptables -t nat -A POSTROUTING -o en+ -s -j MASQUERADE
| sysctl net.ipv4.ip_forward=1
| Linux network NS (vpn1 /
| ---------------------------------------------------------------
| openVPN (tun0 /
| ---------------------------------------------------------------
| server running on port 1234
| ---------------------------------------------------------------