blob: 61013f2aec4f96338e3a82be8534b380d5a68b8a [file] [log] [blame]
Daniel Drowna45056e2012-03-23 10:42:54 -05001/*
2 * Copyright 2011 Daniel Drown
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * ipv6.c - takes ipv6 packets, finds their headers, and then calls translation functions on them
17 */
18#include <string.h>
19
20#include <netinet/in.h>
21#include <netinet/ip.h>
22#include <netinet/ip_icmp.h>
23#include <netinet/udp.h>
24#include <netinet/tcp.h>
25#include <netinet/ip6.h>
26#include <netinet/icmp6.h>
27#include <linux/icmp.h>
28
29#include "translate.h"
30#include "checksum.h"
31#include "ipv6.h"
32#include "logging.h"
33#include "dump.h"
34#include "config.h"
35#include "debug.h"
36
37/* function: icmp6_packet
38 * takes an icmp6 packet and sets it up for translation
39 * fd - tun interface fd
40 * packet - ip payload
41 * len - size of ip payload
42 * ip6 - ip6 header
43 */
44void icmp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) {
45 struct icmp6_hdr icmp6;
46 const char *payload;
47 size_t payload_size;
48
49 if(len < sizeof(icmp6)) {
50 logmsg_dbg(ANDROID_LOG_ERROR,"icmp6_packet/(too small)");
51 return;
52 }
53
54 memcpy(&icmp6, packet, sizeof(icmp6));
55 payload = packet + sizeof(icmp6);
56 payload_size = len - sizeof(icmp6);
57
58 icmp6_to_icmp(fd, ip6, &icmp6, payload, payload_size);
59}
60
61/* function: tcp6_packet
62 * takes a tcp packet and sets it up for translation
63 * fd - tun interface fd
64 * packet - ip payload
65 * len - size of ip payload
66 * ip6 - ip6 header
67 */
68void tcp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) {
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090069 const struct tcphdr *tcp = (const struct tcphdr *) packet;
Daniel Drowna45056e2012-03-23 10:42:54 -050070 const char *payload;
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090071 size_t payload_size, header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -050072
73 if(len < sizeof(tcp)) {
74 logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/(too small)");
75 return;
76 }
77
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090078 if(tcp->doff < 5) {
79 logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set to less than 5: %x", tcp->doff);
Daniel Drowna45056e2012-03-23 10:42:54 -050080 return;
81 }
82
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090083 if((size_t) tcp->doff*4 > len) {
84 logmsg_dbg(ANDROID_LOG_ERROR,"tcp6_packet/tcp header length set too large: %x", tcp->doff);
Daniel Drowna45056e2012-03-23 10:42:54 -050085 return;
86 }
87
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090088 header_size = tcp->doff * 4;
89 payload = packet + header_size;
90 payload_size = len - header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -050091
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090092 tcp6_to_tcp(fd, ip6, tcp, header_size, payload, payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -050093}
94
95/* function: udp6_packet
96 * takes a udp packet and sets it up for translation
97 * fd - tun interface fd
98 * packet - ip payload
99 * len - size of ip payload
100 * ip6 - ip6 header
101 */
102void udp6_packet(int fd, const char *packet, size_t len, struct ip6_hdr *ip6) {
103 struct udphdr udp;
104 const char *payload;
105 size_t payload_size;
106
107 if(len < sizeof(udp)) {
108 logmsg_dbg(ANDROID_LOG_ERROR,"udp6_packet/(too small)");
109 return;
110 }
111
112 memcpy(&udp, packet, sizeof(udp));
113 payload = packet + sizeof(udp);
114 payload_size = len - sizeof(udp);
115
116 udp6_to_udp(fd,ip6,&udp,payload,payload_size);
117}
118
119/* function: log_bad_address
120 * logs a bad address to android's log buffer if debugging is turned on
121 * fmt - printf-style format, use %s to place the address
122 * badaddr - the bad address in question
123 */
124void log_bad_address(const char *fmt, const struct in6_addr *badaddr) {
125#if CLAT_DEBUG
126 char badaddr_str[INET6_ADDRSTRLEN];
127
128 inet_ntop(AF_INET6, badaddr, badaddr_str, sizeof(badaddr_str));
129 logmsg_dbg(ANDROID_LOG_ERROR,fmt,badaddr_str);
130#endif
131}
132
133/* function: ipv6_packet
134 * takes an ipv6 packet and hands it off to the layer 4 protocol function
135 * fd - tun interface fd
136 * packet - packet data
137 * len - size of packet
138 */
139void ipv6_packet(int fd, const char *packet, size_t len) {
140 struct ip6_hdr header;
141 const char *next_header;
142 size_t len_left;
143 int i;
144
145 if(len < sizeof(header)) {
146 logmsg_dbg(ANDROID_LOG_ERROR,"ipv6_packet/too short for an ip6 header");
147 return;
148 }
149
150 memcpy(&header, packet, sizeof(header));
151
152 next_header = packet + sizeof(header);
153 len_left = len - sizeof(header);
154
155 if(IN6_IS_ADDR_MULTICAST(&header.ip6_dst)) {
156 log_bad_address("ipv6_packet/multicast %s", &header.ip6_dst);
157 return; // silently ignore
158 }
159
160 for(i = 0; i < 3; i++) {
161 if(header.ip6_src.s6_addr32[i] != Global_Clatd_Config.plat_subnet.s6_addr32[i]) {
162 log_bad_address("ipv6_packet/wrong source address: %s", &header.ip6_src);
163 return;
164 }
165 }
166 if(!IN6_ARE_ADDR_EQUAL(&header.ip6_dst, &Global_Clatd_Config.ipv6_local_subnet)) {
167 log_bad_address("ipv6_packet/wrong destination address: %s", &header.ip6_dst);
168 return;
169 }
170
171 // does not support IPv6 extension headers, this will drop any packet with them
172 if(header.ip6_nxt == IPPROTO_ICMPV6) {
173 icmp6_packet(fd,next_header,len_left,&header);
174 } else if(header.ip6_nxt == IPPROTO_TCP) {
175 tcp6_packet(fd,next_header,len_left,&header);
176 } else if(header.ip6_nxt == IPPROTO_UDP) {
177 udp6_packet(fd,next_header,len_left,&header);
178 } else {
179#if CLAT_DEBUG
180 logmsg(ANDROID_LOG_ERROR,"ipv6_packet/unknown next header type: %x",header.ip6_nxt);
181 logcat_hexdump("ipv6/nxthdr", packet, len);
182#endif
183 }
184}