mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-20 07:00:05 +01:00
bpf: clat: rework rewrite_icmpv6()
This commit is contained in:
parent
97cd4def69
commit
6d47e6acf4
1 changed files with 38 additions and 48 deletions
|
|
@ -376,85 +376,89 @@ csum_fold_helper(__u32 csum)
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
rewrite_icmpv6(struct ipv6hdr *ip6h, struct __sk_buff *skb)
|
rewrite_icmpv6(struct __sk_buff *skb)
|
||||||
{
|
{
|
||||||
void *data_end = SKB_DATA_END(skb);
|
void *data_end = SKB_DATA_END(skb);
|
||||||
|
void *data = SKB_DATA(skb);
|
||||||
struct icmp6hdr *icmp6;
|
struct icmp6hdr *icmp6;
|
||||||
struct icmphdr icmp;
|
struct icmphdr *icmp;
|
||||||
struct icmphdr *new_icmp;
|
struct icmphdr icmp_buf; /* buffer for the new ICMPv4 header */
|
||||||
|
struct icmp6hdr icmp6_buf; /* copy of the old ICMPv6 header */
|
||||||
|
struct ipv6hdr *ip6h;
|
||||||
__u32 mtu;
|
__u32 mtu;
|
||||||
__u32 ptr;
|
__u32 ptr;
|
||||||
|
|
||||||
icmp6 = (void *) (ip6h + 1);
|
icmp6 = data + sizeof(struct ethhdr) + sizeof(struct ipv6hdr);
|
||||||
if (icmp6 + 1 > data_end)
|
if (icmp6 + 1 > data_end)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
new_icmp = (void *) icmp6;
|
icmp6_buf = *icmp6;
|
||||||
icmp = *new_icmp; // TODO avoid these copies?
|
icmp = (void *) icmp6;
|
||||||
|
icmp_buf = *icmp;
|
||||||
|
|
||||||
/* These translations are defined in RFC6145 section 5.2 */
|
/* These translations are defined in RFC6145 section 5.2 */
|
||||||
switch (icmp6->icmp6_type) {
|
switch (icmp6->icmp6_type) {
|
||||||
case ICMPV6_ECHO_REQUEST:
|
case ICMPV6_ECHO_REQUEST:
|
||||||
icmp.type = ICMP_ECHO;
|
icmp_buf.type = ICMP_ECHO;
|
||||||
break;
|
break;
|
||||||
case ICMPV6_ECHO_REPLY:
|
case ICMPV6_ECHO_REPLY:
|
||||||
icmp.type = ICMP_ECHOREPLY;
|
icmp_buf.type = ICMP_ECHOREPLY;
|
||||||
break;
|
break;
|
||||||
case ICMPV6_DEST_UNREACH:
|
case ICMPV6_DEST_UNREACH:
|
||||||
icmp.type = ICMP_DEST_UNREACH;
|
icmp_buf.type = ICMP_DEST_UNREACH;
|
||||||
switch (icmp6->icmp6_code) {
|
switch (icmp6->icmp6_code) {
|
||||||
case ICMPV6_NOROUTE:
|
case ICMPV6_NOROUTE:
|
||||||
case ICMPV6_NOT_NEIGHBOUR:
|
case ICMPV6_NOT_NEIGHBOUR:
|
||||||
case ICMPV6_ADDR_UNREACH:
|
case ICMPV6_ADDR_UNREACH:
|
||||||
icmp.code = ICMP_HOST_UNREACH;
|
icmp_buf.code = ICMP_HOST_UNREACH;
|
||||||
break;
|
break;
|
||||||
case ICMPV6_ADM_PROHIBITED:
|
case ICMPV6_ADM_PROHIBITED:
|
||||||
icmp.code = ICMP_HOST_ANO;
|
icmp_buf.code = ICMP_HOST_ANO;
|
||||||
break;
|
break;
|
||||||
case ICMPV6_PORT_UNREACH:
|
case ICMPV6_PORT_UNREACH:
|
||||||
icmp.code = ICMP_PORT_UNREACH;
|
icmp_buf.code = ICMP_PORT_UNREACH;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ICMPV6_PKT_TOOBIG:
|
case ICMPV6_PKT_TOOBIG:
|
||||||
icmp.type = ICMP_DEST_UNREACH;
|
icmp_buf.type = ICMP_DEST_UNREACH;
|
||||||
icmp.code = ICMP_FRAG_NEEDED;
|
icmp_buf.code = ICMP_FRAG_NEEDED;
|
||||||
|
|
||||||
mtu = bpf_htonl(icmp6->icmp6_mtu) - 20;
|
mtu = bpf_htonl(icmp6->icmp6_mtu) - 20;
|
||||||
if (mtu > 0xffff)
|
if (mtu > 0xffff)
|
||||||
return -1;
|
return -1;
|
||||||
icmp.un.frag.mtu = bpf_htons(mtu);
|
icmp_buf.un.frag.mtu = bpf_htons(mtu);
|
||||||
break;
|
break;
|
||||||
case ICMPV6_TIME_EXCEED:
|
case ICMPV6_TIME_EXCEED:
|
||||||
icmp.type = ICMP_TIME_EXCEEDED;
|
icmp_buf.type = ICMP_TIME_EXCEEDED;
|
||||||
break;
|
break;
|
||||||
case ICMPV6_PARAMPROB:
|
case ICMPV6_PARAMPROB:
|
||||||
switch (icmp6->icmp6_code) {
|
switch (icmp6->icmp6_code) {
|
||||||
case 0:
|
case 0:
|
||||||
icmp.type = ICMP_PARAMETERPROB;
|
icmp_buf.type = ICMP_PARAMETERPROB;
|
||||||
icmp.code = 0;
|
icmp_buf.code = 0;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
icmp.type = ICMP_DEST_UNREACH;
|
icmp_buf.type = ICMP_DEST_UNREACH;
|
||||||
icmp.code = ICMP_PROT_UNREACH;
|
icmp_buf.code = ICMP_PROT_UNREACH;
|
||||||
ptr = bpf_ntohl(icmp6->icmp6_pointer);
|
ptr = bpf_ntohl(icmp6->icmp6_pointer);
|
||||||
/* Figure 6 in RFC6145 - using if statements b/c of
|
/* Figure 6 in RFC6145 - using if statements b/c of
|
||||||
* range at the bottom
|
* range at the bottom
|
||||||
*/
|
*/
|
||||||
if (ptr == 0 || ptr == 1)
|
if (ptr == 0 || ptr == 1)
|
||||||
icmp.un.reserved[0] = ptr;
|
icmp_buf.un.reserved[0] = ptr;
|
||||||
else if (ptr == 4 || ptr == 5)
|
else if (ptr == 4 || ptr == 5)
|
||||||
icmp.un.reserved[0] = 2;
|
icmp_buf.un.reserved[0] = 2;
|
||||||
else if (ptr == 6)
|
else if (ptr == 6)
|
||||||
icmp.un.reserved[0] = 9;
|
icmp_buf.un.reserved[0] = 9;
|
||||||
else if (ptr == 7)
|
else if (ptr == 7)
|
||||||
icmp.un.reserved[0] = 8;
|
icmp_buf.un.reserved[0] = 8;
|
||||||
else if (ptr >= 8 && ptr <= 23)
|
else if (ptr >= 8 && ptr <= 23)
|
||||||
icmp.un.reserved[0] = 12;
|
icmp_buf.un.reserved[0] = 12;
|
||||||
else if (ptr >= 24 && ptr <= 39)
|
else if (ptr >= 24 && ptr <= 39)
|
||||||
icmp.un.reserved[0] = 16;
|
icmp_buf.un.reserved[0] = 16;
|
||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
break;
|
break;
|
||||||
|
|
@ -466,7 +470,12 @@ rewrite_icmpv6(struct ipv6hdr *ip6h, struct __sk_buff *skb)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
*new_icmp = icmp;
|
*icmp = icmp_buf;
|
||||||
|
ip6h = data + sizeof(struct ethhdr);
|
||||||
|
update_icmp_checksum(skb, ip6h, &icmp6_buf, icmp, false);
|
||||||
|
|
||||||
|
/* FIXME: also need to rewrite IP header embedded in ICMP error */
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -531,29 +540,10 @@ clat_handle_v6(struct __sk_buff *skb)
|
||||||
|
|
||||||
switch (dst_hdr.protocol) {
|
switch (dst_hdr.protocol) {
|
||||||
case IPPROTO_ICMPV6:
|
case IPPROTO_ICMPV6:
|
||||||
{
|
if (rewrite_icmpv6(skb))
|
||||||
struct icmphdr *new_icmp;
|
|
||||||
struct icmp6hdr old_icmp6;
|
|
||||||
|
|
||||||
new_icmp = (void *) (ip6h + 1);
|
|
||||||
if (new_icmp + 1 > data_end)
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
old_icmp6 = *((struct icmp6hdr *) (void *) new_icmp);
|
|
||||||
if (rewrite_icmpv6(ip6h, skb))
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
/* TODO: also need to rewrite IP header embedded in ICMP error */
|
|
||||||
|
|
||||||
if ((void *) (new_icmp + 1) > data_end)
|
|
||||||
goto icmp_out;
|
|
||||||
|
|
||||||
update_icmp_checksum(skb, ip6h, &old_icmp6, new_icmp, false);
|
|
||||||
|
|
||||||
icmp_out:
|
|
||||||
dst_hdr.protocol = IPPROTO_ICMP;
|
dst_hdr.protocol = IPPROTO_ICMP;
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case IPPROTO_TCP:
|
case IPPROTO_TCP:
|
||||||
case IPPROTO_UDP:
|
case IPPROTO_UDP:
|
||||||
update_l4_checksum(skb, ip6h, &dst_hdr, dst_hdr.protocol, false);
|
update_l4_checksum(skb, ip6h, &dst_hdr, dst_hdr.protocol, false);
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue