From c7d08bea342b95105f6bd787aa8df7663aa4cebc Mon Sep 17 00:00:00 2001 From: sven-ola Date: Fri, 15 Oct 2010 10:21:29 +0000 Subject: git-svn-id: https://map66.svn.sourceforge.net/svnroot/map66@42 3484d885-4da6-438d-b19d-107d078dd756 --- ip6t_MAP66.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 58 insertions(+), 10 deletions(-) diff --git a/ip6t_MAP66.c b/ip6t_MAP66.c index 66f5172..2f880e5 100644 --- a/ip6t_MAP66.c +++ b/ip6t_MAP66.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "ip6t_MAP66.h" @@ -36,16 +37,31 @@ static inline u_int16_t csum16(const u_int16_t *buf, int len) static void map16( struct in6_addr* addr, const struct in6_addr* to, - int len, - u_int16_t csum) + int len_to, + u_int16_t csum_to) { - csum = add16( - *((u_int16_t*)addr + len), - add16(csum16((const u_int16_t *)addr, len), csum) + csum_to = add16( + *((u_int16_t*)addr + len_to), + add16(csum16((const u_int16_t *)addr, len_to), csum_to) ); - if (csum == 0xffff) csum = 0x0000; - *((u_int16_t *)addr + len) = csum; - memcpy(addr, to, sizeof(u_int16_t) * len); + if (csum_to == 0xffff) csum_to = 0x0000; + *((u_int16_t *)addr + len_to) = csum_to; + memcpy(addr, to, sizeof(u_int16_t) * len_to); +} + +/* Perform mapping with csum update */ +static void map_csum( + struct in6_addr* addr, + const struct in6_addr* to, + int len_to, + u_int16_t csum_to, + u_int16_t* csum_transport) +{ + *csum_transport = ~add16( + ~csum_to, + add16(~*csum_transport, ~csum16((u_int16_t *)&addr, len_to)) + ); + memcpy(addr, to, sizeof(u_int16_t) * len_to); } #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) @@ -123,6 +139,7 @@ static unsigned int MAP66_tg6( struct sk_buff *skb, const struct xt_target_param *par) { + u_int16_t* csum_transport = NULL; struct ipv6hdr *hdr = ipv6_hdr(skb); const struct ip6t_MAP66_info *info = par->targinfo; @@ -151,13 +168,44 @@ static unsigned int MAP66_tg6( hdr = ipv6_hdr(skb); #endif + if (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags)) { + u8 nexthdr = hdr->nexthdr; + int hoff = ipv6_skip_exthdr(skb, sizeof(struct ipv6hdr), &nexthdr); + if (hoff < 0) { + pr_devel("MAP66: Unsupported packet dropped\n"); + return NF_DROP; + } + switch(nexthdr) { + case IPPROTO_TCP: + csum_transport = skb_header_pointer( + skb, hoff+offsetof(struct tcphdr, check), 0, NULL); + break; + case IPPROTO_UDP: + case IPPROTO_UDPLITE: + csum_transport = skb_header_pointer( + skb, hoff+offsetof(struct udphdr, check), 0, NULL); + break; + case IPPROTO_DCCP: + csum_transport = skb_header_pointer( + skb, hoff+offsetof(struct dccp_hdr, dccph_checksum), 0, NULL); + break; + case IPPROTO_ICMPV6: + csum_transport = skb_header_pointer( + skb, hoff+offsetof(struct icmp6hdr, icmp6_cksum), 0, NULL); + break; + default: + pr_devel("MAP66: Unsupported protocol %d\n", nexthdr); + return NF_DROP; + } + } + if (0 != (IP6T_MAP66_OPT_DST_TO & info->mapflags)) { pr_devel("MAP66: DST_TO, ip_summed=%d\n", skb->ip_summed); if (0 != (IP6T_MAP66_OPT_NOCHECK & info->mapflags) || !is_my_ipv6_addr( NF_INET_PRE_ROUTING == par->hooknum ? par->in : par->out, &hdr->daddr)) { if (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags)) { - memcpy(&hdr->daddr, &info->pfix_dst_to, sizeof(u_int16_t) * info->pfix_dst_len); + map_csum(&hdr->daddr, &info->pfix_dst_to, info->pfix_dst_len, info->pfix_dst_csum, csum_transport); } else { map16(&hdr->daddr, &info->pfix_dst_to, info->pfix_dst_len, info->pfix_dst_csum); @@ -168,7 +216,7 @@ static unsigned int MAP66_tg6( if (0 != (IP6T_MAP66_OPT_SRC_TO & info->mapflags)) { pr_devel("MAP66: SRC_TO, ip_summed=%d\n", skb->ip_summed); if (0 != (IP6T_MAP66_OPT_CSUM & info->mapflags)) { - memcpy(&hdr->saddr, &info->pfix_src_to, sizeof(u_int16_t) * info->pfix_src_len); + map_csum(&hdr->saddr, &info->pfix_src_to, info->pfix_src_len, info->pfix_src_csum, csum_transport); } else { map16(&hdr->saddr, &info->pfix_src_to, info->pfix_src_len, info->pfix_src_csum); -- cgit v1.2.3