Sunday, November 23, 2008

Iptables and iproute2

  1. Declaration of variables in shell script:

    WAN=eth1
    VPN=tun0
    PROT=tcp
    WANPORT=3389
    RHOST=remote hostname
    RIP=`getent hosts $RHOST |cut -d' ' -f1`
    WANIP=`ip addr list $WAN |grep "inet " |cut -d' ' -f6|cut -d/ -f1`
    TBL=vpn
    PRIO=500
    
    #cat /etc/iproute2/rt_tables
    #
    # reserved values
    #
    255     local
    254     main
    253     default
    0       unspec
    #
    # local
    #
    8       vpn
    
  2. Routing based on destination port and IP address (required route to the remote IP is via a VPN tunnel interface). I first modified the script /etc/vpnc/vpnc-script to limit its *_route functions only updating the routing table $TBL.

    Since the NAT clients need to connect to the remote desktop service of RIP via the tunnel, their packets should be mangled before routing/forwarding when they arrive at the PREROUTING chain:
    CHAIN=PREROUTING
    iptables -t mangle -A ${CHAIN} -p $PROT -d $RIP --dport $WANPORT -j MARK --set-mark 1
    #iptables -t mangle -A ${CHAIN} -m mark --mark 1 -j LOG --log-level DEBUG --log-prefix "fwmark 1: "


    The packets originated from the router will most likely arrive at the WAN interface and the OUTPUT chain of mangle table after the routing decision is made by kernel according to the table 3-2 of this article. Therefore their routing are not affected. In order to make it work, the packets need to arrive at the LAN interface and the OUTPUT chain of the mangle table.
    CHAIN=OUTPUT
    iptables -t mangle -A ${CHAIN} -p $PROT -d $RIP --dport $WANPORT -j MARK --set-mark 1
    #iptables -t mangle -A ${CHAIN} -m mark --mark 1 -j LOG --log-level DEBUG --log-prefix "fwmark 1: "

    This can be achieved by binding the socket to the LAN interface first then send the packets.
    #IP address of the LAN interface
    my $raddr = inet_aton("192.168.0.1");
    # create and bind the socket
    my $proto = getprotobyname('tcp');
    socket(SOCKET, PF_INET, SOCK_STREAM, $proto) or die "socket: $!";
    bind(SOCKET, pack_sockaddr_in(0, $raddr)) or die "bind: $!";


    All the marked packets will then be routed by the following rule:
    ip rule del prio $PRIO
    ip rule add prio $PRIO from fwmark 1 table $TBL


    #ip rule
    0: from all lookup local
    500: from all fwmark 0x1 lookup vpn
    32766: from all lookup main
    32767: from all lookup default

    #ip route show table vpn
  3. Block Ping requests from WAN:
    iptables -A INPUT -p icmp --icmp-type 8 -i $WAN -m state --state NEW,ESTABLISHED,RELATED -j DROP
  4. Check log target of iptables:
    iptables -n -L -v|grep -i log
    cat /etc/shorewall/policy
    #SOURCE         DEST            POLICY          LOG LEVEL       LIMIT:BURST      
    loc     net     ACCEPT
    loc     fw      ACCEPT
    fw      loc     ACCEPT
    fw      net     ACCEPT
    #net    all     DROP    info
    #Disable logging of dropped packets
    net     all     DROP
    all     all     REJECT  info
    

Saturday, November 15, 2008

Enable NAT through tun0 (VPN) by iptables or shorewall

Assuming the interface WAN is used to connect to internet and interface VPN is created by VPN client
WAN=eth1
VPN=tun0
LAN=eth0
#Enable packet forwarding to function as a router
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables --append FORWARD --in-interface $LAN -j ACCEPT
#Enable MASQUERADE to function as a NAT router
iptables --table nat --append POSTROUTING --out-interface $WAN -j MASQUERADE
iptables --table nat --append POSTROUTING --out-interface $VPN -j MASQUERADE

With shorewall, I had the following instead:
/etc/shorewall/interfaces:
#ZONE   INTERFACE       BROADCAST       OPTIONS 
net tun0 detect

/etc/shorewall/masq
#INTERFACE              SOURCE          ADDRESS         PROTO   PORT(S) IPSEC   MARK
tun0    192.168.0.0/24