diff options
author | Lorenzo Colitti <lorenzo@google.com> | 2014-05-13 13:17:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-05-13 18:35:08 -0400 |
commit | e110861f86094cd78cc85593b873970092deb43a (patch) | |
tree | 535ecba8f65cefb68da0846ff54801bb32bf3c9e /net/ipv6 | |
parent | 87e067cda6df60b55cea0239c2f3cee81e9f46df (diff) |
net: add a sysctl to reflect the fwmark on replies
Kernel-originated IP packets that have no user socket associated
with them (e.g., ICMP errors and echo replies, TCP RSTs, etc.)
are emitted with a mark of zero. Add a sysctl to make them have
the same mark as the packet they are replying to.
This allows an administrator that wishes to do so to use
mark-based routing, firewalling, etc. for these replies by
marking the original packets inbound.
Tested using user-mode linux:
- ICMP/ICMPv6 echo replies and errors.
- TCP RST packets (IPv4 and IPv6).
Signed-off-by: Lorenzo Colitti <lorenzo@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/icmp.c | 6 | ||||
-rw-r--r-- | net/ipv6/sysctl_net_ipv6.c | 7 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 1 |
3 files changed, 14 insertions, 0 deletions
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 8d3952796d39..f6c84a6eb238 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c | |||
@@ -400,6 +400,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
400 | int len; | 400 | int len; |
401 | int hlimit; | 401 | int hlimit; |
402 | int err = 0; | 402 | int err = 0; |
403 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | ||
403 | 404 | ||
404 | if ((u8 *)hdr < skb->head || | 405 | if ((u8 *)hdr < skb->head || |
405 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) | 406 | (skb_network_header(skb) + sizeof(*hdr)) > skb_tail_pointer(skb)) |
@@ -466,6 +467,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
466 | fl6.daddr = hdr->saddr; | 467 | fl6.daddr = hdr->saddr; |
467 | if (saddr) | 468 | if (saddr) |
468 | fl6.saddr = *saddr; | 469 | fl6.saddr = *saddr; |
470 | fl6.flowi6_mark = mark; | ||
469 | fl6.flowi6_oif = iif; | 471 | fl6.flowi6_oif = iif; |
470 | fl6.fl6_icmp_type = type; | 472 | fl6.fl6_icmp_type = type; |
471 | fl6.fl6_icmp_code = code; | 473 | fl6.fl6_icmp_code = code; |
@@ -474,6 +476,7 @@ static void icmp6_send(struct sk_buff *skb, u8 type, u8 code, __u32 info) | |||
474 | sk = icmpv6_xmit_lock(net); | 476 | sk = icmpv6_xmit_lock(net); |
475 | if (sk == NULL) | 477 | if (sk == NULL) |
476 | return; | 478 | return; |
479 | sk->sk_mark = mark; | ||
477 | np = inet6_sk(sk); | 480 | np = inet6_sk(sk); |
478 | 481 | ||
479 | if (!icmpv6_xrlim_allow(sk, type, &fl6)) | 482 | if (!icmpv6_xrlim_allow(sk, type, &fl6)) |
@@ -551,6 +554,7 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
551 | int err = 0; | 554 | int err = 0; |
552 | int hlimit; | 555 | int hlimit; |
553 | u8 tclass; | 556 | u8 tclass; |
557 | u32 mark = IP6_REPLY_MARK(net, skb->mark); | ||
554 | 558 | ||
555 | saddr = &ipv6_hdr(skb)->daddr; | 559 | saddr = &ipv6_hdr(skb)->daddr; |
556 | 560 | ||
@@ -569,11 +573,13 @@ static void icmpv6_echo_reply(struct sk_buff *skb) | |||
569 | fl6.saddr = *saddr; | 573 | fl6.saddr = *saddr; |
570 | fl6.flowi6_oif = skb->dev->ifindex; | 574 | fl6.flowi6_oif = skb->dev->ifindex; |
571 | fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; | 575 | fl6.fl6_icmp_type = ICMPV6_ECHO_REPLY; |
576 | fl6.flowi6_mark = mark; | ||
572 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); | 577 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |
573 | 578 | ||
574 | sk = icmpv6_xmit_lock(net); | 579 | sk = icmpv6_xmit_lock(net); |
575 | if (sk == NULL) | 580 | if (sk == NULL) |
576 | return; | 581 | return; |
582 | sk->sk_mark = mark; | ||
577 | np = inet6_sk(sk); | 583 | np = inet6_sk(sk); |
578 | 584 | ||
579 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) | 585 | if (!fl6.flowi6_oif && ipv6_addr_is_multicast(&fl6.daddr)) |
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c index 7f405a168822..058f3eca2e53 100644 --- a/net/ipv6/sysctl_net_ipv6.c +++ b/net/ipv6/sysctl_net_ipv6.c | |||
@@ -38,6 +38,13 @@ static struct ctl_table ipv6_table_template[] = { | |||
38 | .mode = 0644, | 38 | .mode = 0644, |
39 | .proc_handler = proc_dointvec | 39 | .proc_handler = proc_dointvec |
40 | }, | 40 | }, |
41 | { | ||
42 | .procname = "fwmark_reflect", | ||
43 | .data = &init_net.ipv6.sysctl.fwmark_reflect, | ||
44 | .maxlen = sizeof(int), | ||
45 | .mode = 0644, | ||
46 | .proc_handler = proc_dointvec | ||
47 | }, | ||
41 | { } | 48 | { } |
42 | }; | 49 | }; |
43 | 50 | ||
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 3a267bf14f2f..c54976a44425 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c | |||
@@ -812,6 +812,7 @@ static void tcp_v6_send_response(struct sk_buff *skb, u32 seq, u32 ack, u32 win, | |||
812 | fl6.flowi6_oif = inet6_iif(skb); | 812 | fl6.flowi6_oif = inet6_iif(skb); |
813 | else | 813 | else |
814 | fl6.flowi6_oif = oif; | 814 | fl6.flowi6_oif = oif; |
815 | fl6.flowi6_mark = IP6_REPLY_MARK(net, skb->mark); | ||
815 | fl6.fl6_dport = t1->dest; | 816 | fl6.fl6_dport = t1->dest; |
816 | fl6.fl6_sport = t1->source; | 817 | fl6.fl6_sport = t1->source; |
817 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); | 818 | security_skb_classify_flow(skb, flowi6_to_flowi(&fl6)); |