blob: 243f9d0675331461bca908cc76ffc6872d8b2d3a [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 * ipv4.c - takes ipv4 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 "ipv4.h"
32#include "logging.h"
33#include "debug.h"
34
35/* function: icmp_packet
36 * takes an icmp packet and sets it up for translation
37 * fd - tun interface fd
38 * packet - ip payload
39 * len - size of ip payload
40 * ip - ip header
41 */
42void icmp_packet(int fd, const char *packet, size_t len, struct iphdr *ip) {
43 struct icmphdr icmp;
44 const char *payload;
45 size_t payload_size;
46
47 if(len < sizeof(icmp)) {
48 logmsg_dbg(ANDROID_LOG_ERROR,"icmp_packet/(too small)");
49 return;
50 }
51
52 memcpy(&icmp, packet, sizeof(icmp));
53 payload = packet + sizeof(icmp);
54 payload_size = len - sizeof(icmp);
55
56 icmp_to_icmp6(fd,ip,&icmp,payload,payload_size);
57}
58
59/* function: tcp_packet
60 * takes a tcp packet and sets it up for translation
61 * fd - tun interface fd
62 * packet - ip payload
63 * len - size of ip payload
64 * ip - ip header
65 */
66void tcp_packet(int fd, const char *packet, size_t len, struct iphdr *ip) {
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090067 const struct tcphdr *tcp = (const struct tcphdr *) packet;
Daniel Drowna45056e2012-03-23 10:42:54 -050068 const char *payload;
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090069 size_t payload_size, header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -050070
71 if(len < sizeof(tcp)) {
72 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/(too small)");
73 return;
74 }
75
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090076 if(tcp->doff < 5) {
77 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set to less than 5: %x", tcp->doff);
Daniel Drowna45056e2012-03-23 10:42:54 -050078 return;
79 }
80
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090081 if((size_t) tcp->doff*4 > len) {
82 logmsg_dbg(ANDROID_LOG_ERROR,"tcp_packet/tcp header length set too large: %x", tcp->doff);
Daniel Drowna45056e2012-03-23 10:42:54 -050083 return;
84 }
85
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090086 header_size = tcp->doff * 4;
87 payload = packet + header_size;
88 payload_size = len - header_size;
Daniel Drowna45056e2012-03-23 10:42:54 -050089
Lorenzo Colitti5cc877d2013-04-08 19:12:43 +090090 tcp_to_tcp6(fd, ip, tcp, header_size, payload, payload_size);
Daniel Drowna45056e2012-03-23 10:42:54 -050091}
92
93/* function: udp_packet
94 * takes a udp packet and sets it up for translation
95 * fd - tun interface fd
96 * packet - ip payload
97 * len - size of ip payload
98 * ip - ip header
99 */
100void udp_packet(int fd, const char *packet, size_t len, const struct iphdr *ip) {
101 struct udphdr udp;
102 const char *payload;
103 size_t payload_size;
104
105 if(len < sizeof(udp)) {
106 logmsg_dbg(ANDROID_LOG_ERROR,"udp_packet/(too small)");
107 return;
108 }
109
110 memcpy(&udp, packet, sizeof(udp));
111 payload = packet + sizeof(udp);
112 payload_size = len - sizeof(udp);
113
114 udp_to_udp6(fd,ip,&udp,payload,payload_size);
115}
116
117/* function: ip_packet
118 * takes an ip packet and hands it off to the layer 4 protocol function
119 * fd - tun interface fd
120 * packet - packet data
121 * len - size of packet
122 */
123void ip_packet(int fd, const char *packet, size_t len) {
124 struct iphdr header;
125 uint16_t frag_flags;
126 const char *next_header;
127 size_t len_left;
128
129 if(len < sizeof(header)) {
130 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/too short for an ip header");
131 return;
132 }
133
134 memcpy(&header, packet, sizeof(header));
135
136 frag_flags = ntohs(header.frag_off);
137 if(frag_flags & IP_MF) { // this could theoretically be supported, but isn't
138 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/more fragments set, dropping");
139 return;
140 }
141
142 if(header.ihl < 5) {
143 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/ip header length set to less than 5: %x",header.ihl);
144 return;
145 }
146
147 if((size_t)header.ihl*4 > len) { // ip header length larger than entire packet
148 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/ip header length set too large: %x",header.ihl);
149 return;
150 }
151
152 if(header.version != 4) {
153 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/ip header version not 4: %x",header.version);
154 return;
155 }
156
157 /* rfc6145 - If any IPv4 options are present in the IPv4 packet, they MUST be
158 * ignored and the packet translated normally; there is no attempt to
159 * translate the options.
160 */
161
162 next_header = packet + header.ihl*4;
163 len_left = len - header.ihl*4;
164
165 if(header.protocol == IPPROTO_ICMP) {
166 icmp_packet(fd,next_header,len_left,&header);
167 } else if(header.protocol == IPPROTO_TCP) {
168 tcp_packet(fd,next_header,len_left,&header);
169 } else if(header.protocol == IPPROTO_UDP) {
170 udp_packet(fd,next_header,len_left,&header);
171 } else {
172#if CLAT_DEBUG
173 logmsg_dbg(ANDROID_LOG_ERROR,"ip_packet/unknown protocol: %x",header.protocol);
174 logcat_hexdump("ipv4/protocol", packet, len);
175#endif
176 }
177}