The policy routing doesn't work because: (local process) -> (routing decision) -> [raw:output] -> contrack -> [mangle:output] -> (reroute check) -> [nat:output] -> [filter:output] -> ...
When the local process generates a packet, the network stack takes the routing decision really early on. In our case earlier then we are able to mark them with iptables. The marking happens in the mangle table and therefore the policy routing table is not considered at this point. My naive assumption was that the reroute check would be done unconditionally. Unfortunately, this is not true. The reroute check is only done if the packet was modified in the mangle output chain. So for example for the ICMP protocol: net/ipv4/ping.c: ping_v4_sendmsg() ip_route_output_flow() And the rerouting happens here: net/ipv4/netfilter/iptable_mangle.c ipt_mangle_out() ip_route_me_harder() ip_route_output_key() ip_route_output_flow() So let's reroute the packets via iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 192.168.1.100 The policy routing table is not completely useless. For example the process could mark its packet on its own. Another possible way is to have a cgroup controller setting the SO_MARK or we teach the policy routing table to match on sk_classid (cls cgroup controller). Obviously, we don't need both the policy routing table and the NAT rules. But I am reluctant to rip out the policy routing code at this point. Maybe someone is using it already. Reported by: Gianfranco Casanova <gianfranco.casan...@gmail.com> --- src/session.c | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/src/session.c b/src/session.c index 08facc1..388aae7 100644 --- a/src/session.c +++ b/src/session.c @@ -69,6 +69,7 @@ struct connman_session { enum connman_session_id_type id_type; struct firewall_context *fw; + int snat_id; uint32_t mark; int index; char *gateway; @@ -365,6 +366,63 @@ static void add_default_route(struct connman_session *session) DBG("session %p %s", session, strerror(-err)); } +static void del_nat_rules(struct connman_session *session) +{ + int err; + + if (!session->fw || session->snat_id == 0) + return; + + err = __connman_firewall_disable_rule(session->fw, session->snat_id); + if (err < 0) { + DBG("could not disable SNAT rule"); + return; + } + + err = __connman_firewall_remove_rule(session->fw, session->snat_id); + if (err < 0) + DBG("could not remove SNAT rule"); + + + session->snat_id = 0; +} + +static void add_nat_rules(struct connman_session *session) +{ + struct connman_ipconfig *ipconfig; + const char *addr; + char *ifname; + int index, id, err; + + if (!session->fw) + return; + + DBG(""); + + ipconfig = __connman_service_get_ip4config(session->service); + index = __connman_ipconfig_get_index(ipconfig); + ifname = connman_inet_ifname(index); + addr = __connman_ipconfig_get_local(ipconfig); + + id = __connman_firewall_add_rule(session->fw, "nat", "POSTROUTING", + "-o %s -j SNAT --to-source %s", + ifname, addr); + g_free(ifname); + if (id < 0) { + DBG("failed to add SNAT rule"); + return; + } + + err = __connman_firewall_enable_rule(session->fw, id); + if (err < 0) { + DBG("could not enable SNAT rule"); + __connman_firewall_remove_rule(session->fw, id); + return; + } + + session->snat_id = id; +} + static void cleanup_routing_table(struct connman_session *session) { DBG(""); @@ -387,6 +445,12 @@ static void update_routing_table(struct connman_session *session) add_default_route(session); } +static void update_nat_rules(struct connman_session *session) +{ + del_nat_rules(session); + add_nat_rules(session); +} + static void destroy_policy_config(struct connman_session *session) { if (!policy) { @@ -1482,6 +1546,7 @@ static void update_session_state(struct connman_session *session) DBG("session %p state %s", session, state2string(state)); update_routing_table(session); + update_nat_rules(session); session_notify(session); } -- 2.4.3 _______________________________________________ connman mailing list connman@connman.net https://lists.connman.net/mailman/listinfo/connman