It seems that i've found a solution that works for me.
I still have to use
iroute , there seems to be no way to handle the routing entirely in the kernel of the linux-os.
I changed my setup to the following:
This tells the openvpn-server that the linux-client is responsible for the network 192.168.23.0/24
and will route all incoming traffic inside the openvpn-process to this linux-client.
/etc/openvpn/client-config/linux-client:
iroute 192.168.23.0 255.255.255.0
This tells the windows-client to route all traffic for the 192.168.23.0/24 subnet to the openvpn-server.
/etc/openvpn/client-config/windows-client
push "route 192.168.23.0 255.255.255.0"
My idea is to use a network of "unused" addresses to NAT the subnets behind the linux-client(s).
Because there could be more than one subnet with the same addressspace.
If i want to reach a machine in the 172.16.0.0 /24 network behind the linux-client, on the windows-client side i use a "fake" network
of 192.168.23.0 /24 or 192.168.24.0/24 or anything else which is not used in the entire intranet (it should of course be a "private" network).
So in this example, to reach 172.16.0.14 /24 behind the linux-client a route will be set on the windows-client which tells him to reach 192.168.23.14/24 via the openvpn-server address.
The packet with the destination address 192.168.23.14 now gets send to the openvpn-server, "exits" the tun0 interface and enters the kernel routing table. So we have to tell the server what to do with the packet. We tell him that everything for 192.168.23.14 /24 gets routed to the tun0 address, in my case 10.0.0.1.
ip route add to 192.168.23.0/24 via 10.0.0.1
The packet now traverses the openvpn-server and enters the tun0 interface again, so that the openvpn-process takes over. Because we told openvpn with the
iroute statement that the linux-client is responsible for this "fake" network it will route the packet to the openvpn-address (10.0.0.3 in my case) of the linux-client.
The linux client itself must know that it has to alter the incoming packets with destination address 192.168.23.14/24 to 172.16.0.14/24. This is done with iptables rules like this:
iptables -t nat -A PREROUTING -i tun0 -s -d 192.168.23.14 -j DNAT --to-destination 172.16.0.14
iptables -t nat -A POSTROUTING -o eth1 -s -d 172.16.0.14 -j MASQUERADE
We tell the kernel netfilter module to replace the destination ip-address of every incoming packet from tun0 with the destination-ip 192.168.23.14 to the new destination-ip 172.16.0.14.
After that the source address of the packet is also exchanged and the address of the local interface, which is connected to the 172.16.0.0/24 network, is added.
So the packet first looks like this:
Source-IP: 10.0.0.2
Destination-IP: 192.168.23.14
And after the alteration with iptables it looks like this:
Source-IP: 172.16.0.5 (the ip-address of the local interface of the linux-client in the 172.16.0.0/24 network)
Destination-IP: 172.16.0.14 (the ip-address of the client in the target network which i want to reach)
Because of the MASQUERADE functionality iptables is able to modify the packets which now will be send back from the target machine 172.16.0.14 again.
Initially the answering packet looks like:
Source-IP: 172.16.0.14 (ip-address of the client in the target network)
Destination-IP: 172.16.0.5 (ip-address of the linux client which does the NAT)
Now the MASQUERADE is doing its magic and alters the packet like this:
Source-IP: 192.168.23.14 (the fake ip-address to which the windows client sends its packets)
Destination-IP: 10.0.0.2 (the open-vpn address of the windows client)
The downside is the effort in setting this up. Because you have to create a "mapping table" to know which "fake ip" is responsible for which "real ip" behind which client, but in my case it is worth the effort.
Maybe this solution helps somebody else.