1

I have two VPS with one on which I installed OpenVPN Access Server and vpn client on the second one. When I connect the client to the OpenVPN AS, I can't get access to apache which is installed on the client, from its public IP address. My wish is to make some services like apache and postfix available from public internet on the client server while tunneling other services installed on the machine. How can I do that ?

Here is the content of my /etc/iproute2/rt_tables

#  
# reserved values  
#  
255 local  
254 main  
253 default  
0   unspec  
#  
# local  
#  
#1  inr.ruhep
1 inet  

When client disconnected, ip route show gives :

default via <router_ip>  dev <ext_if>  
<netw_addr> via <router_ip>  dev <ext_if>  
<netw_addr> dev <ext_if>  proto kernel  scope link  src <public_ip>  

When client connected, ip route show gives :

0.0.0.0/1 via <private_router_ip> dev <vpn_if>  
default via <router_ip>  dev <ext_if>  
128.0.0.0/1 via <private_router_ip> dev <vpn_if>  
<vpn_addr> dev <vpn_if>  proto kernel  scope link  src <private_ip>  
<vpn_server_public_ip> via <router_ip>  dev <ext_if>  
<netw_addr> via <router_ip>  dev <ext_if>  
<netw_addr> dev <ext_if>  proto kernel  scope link  src <public_ip>  

When client connected, ip addr show gives

1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    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
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: <ext_if>: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether XX:XX:XX:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet <public_ip>/<netmask> brd <ext_broadcast_ip> scope global <ext_if>
       valid_lft forever preferred_lft forever
    inet6 XXXX:XXXX:XXXX:XXXX::XX scope global 
       valid_lft forever preferred_lft forever
    inet6 XXXX::XX:XXXX:XXXX:XXXX/XX scope link 
       valid_lft forever preferred_lft forever
18: <vpn_if>: <POINTOPOINT,MULTICAST,NOARP,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 100
    link/none 
    inet <private_ip>/<netmask> brd <private_broadcast_ip> scope global <vpn_if>
       valid_lft forever preferred_lft forever
1
  • Please also add the output of ip route show table inet just do be sure its correct. I updated my answer, as it turned out that just using MARK on the incoming packets is not enough. The whole connection needs to be marked with CONNMARK to be able to mark the outgoing packets. Check out the new instructions in the iptables section. I can confirm it is working on my test setup.
    – rda
    Jun 7, 2016 at 21:52

2 Answers 2

0

Use policy routing on the client side to do that.

Policy routing

Example policy routing http service (port 80) via internet:

echo "1 inet" >> /etc/iproute2/rt_tables

Add default route to inet routing table

ip route add default via <router_ip> dev <if> table inet
  • <if>: replace with the name of the interface, directly connected to the internet (i.e. eth0)
  • <router_ip>: replace with the IP of the router (gateway), on the internet side subnet. This is the router defined as default gateway, while the client server is not connected via VPN. To get this IP, disconnect/close the VPN client and type: ip route show | grep default

Add a routing rule to send everything marked with fwmark 0x1 to routing table inet

ip rule add from all fwmark 0x1 table inet

Marking packets with iptables for policy routing

Mark packets that have port 80 as destination in the MANGLE table (repeat the ... --dport 80 ... line for any other service/port).

iptables -t mangle -F
iptables -t mangle -A PREROUTING -i <if> -p tcp --dport 80 -j MARK --set-mark 0x1
iptables -t mangle -A PREROUTING -j CONNMARK --save-mark
iptables -t mangle -A OUTPUT -j CONNMARK --restore-mark
iptables -t mangle -A OUTPUT -m connmark --mark 0x1 -j MARK --set-mark 0x1
  • <if>: replace with the name of the interface, directly connected to the internet (i.e. eth0)

These rules do the following:

  1. Flush the mangle table (only required to clear any previously defined rules)
  2. MARK incoming packets on the external interface to a specific port (80)
  3. Set the MARK of the initial packet (previous rule) as value of the CONNMARK (conntrack mark) for all the packets of the connection.
  4. Restore the CONNMARK in the OUTPUT chain.
  5. MARK outgoing packets in the OUTPUT chain where the connection CONNMARK is 0x1. This MARK can be used to match packets in policy routing with fwmark 0x1.
4
  • where should I put those policies ? On the OpenVPN Access Server or on the client side ? Jun 7, 2016 at 8:44
  • I still get a question: what do you mean by <router_ip> in command ip route add default via <router_ip> dev <external_interface> table inet ? Jun 7, 2016 at 10:39
  • I get RTNETLINK answers: File exists when I do ip route add default via <router_ip> dev <ext_if> table inet and still can't access my server from a network external to my virtual private network. Jun 7, 2016 at 13:21
  • @EdouardHINVI, Please add the outputs of the following commands to your question: cat /etc/iproute2/rt_tables, while client disconnected: ip route show, while client connected: ip route show, ip addr show. Maybe obscure your external IP addresses.
    – rda
    Jun 7, 2016 at 14:13
0

I finally solved my issue. Here is how I did it. In OpenVPN Access Server web admin settings, under Routing section of VPN Settings, I checked

No

for question

"Should client Internet traffic be routed through the VPN ?"

Then, I came back on the client side and flushed all previous rules added in mangle table. Then, came the magic ! I am now able to connect to my VPN while my apache is still available to public.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .