OverSim
TunOutDevice.cc
Go to the documentation of this file.
1 //
2 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
3 //
4 // This program is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU General Public License
6 // as published by the Free Software Foundation; either version 2
7 // of the License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 //
18 
24 #include "TunOutDevice.h"
25 #include "IPDatagram_m.h"
26 #include "UDPPacket.h"
27 
29 
30 #if not defined _WIN32 && not defined __APPLE__
31 
32 #include <netinet/ip.h>
33 #include <netinet/udp.h>
34 
35 char* TunOutDevice::encapsulate(cPacket *msg,
36  unsigned int* length,
37  sockaddr** addr,
38  socklen_t* addrlen)
39 {
40  *addr = 0;
41  *addrlen = 0;
42 
43  struct udppseudohdr {
44  uint32_t saddr;
45  uint32_t daddr;
46  uint8_t zero;
47  uint8_t protocol;
48  uint16_t lenght;
49  }*pseudohdr;
50 
51  unsigned int payloadlen;
52  static unsigned int iplen = 20; // we don't generate IP options
53  static unsigned int udplen = 8;
54  cPacket* payloadMsg = NULL;
55  char* buf = NULL, *payload = NULL;
56  uint32_t saddr, daddr;
57  volatile iphdr* ip_buf;
58  volatile udphdr* udp_buf;
59 
60  IPDatagram* IP = check_and_cast<IPDatagram*>(msg);
61 
62  // FIXME: Cast ICMP-Messages
63  UDPPacket* UDP = dynamic_cast<UDPPacket*>(IP->decapsulate());
64  if (!UDP) {
65  EV << "[TunOutDevice::encapsulate()]\n"
66  << " Can't parse non-UDP packets (e.g. ICMP) (yet)"
67  << endl;
68  goto parse_error;
69  }
70 
71  // TODO(?) Handle fragmented packets
72  if( IP->getMoreFragments() ) {
73  EV << "[TunOutDevice::encapsulate()]\n"
74  << " Can't parse fragmented packets"
75  << endl;
76  goto parse_error;
77  }
78  payloadMsg = UDP->decapsulate();
79 
80  // parse payload
81  payload = parser->encapsulatePayload(payloadMsg, &payloadlen);
82  if (!payload ) {
83  EV << "[TunOutDevice::encapsulate()]\n"
84  << " Can't parse packet payload, dropping packet"
85  << endl;
86  goto parse_error;
87  }
88 
89  *length = payloadlen + iplen + udplen;
90  if( *length > mtu ) {
91  EV << "[TunOutDevice::encapsulate()]\n"
92  << " Error: Packet too big! Size = " << *length << " MTU = " << mtu
93  << endl;
94  goto parse_error;
95  }
96 
97  buf = new char[*length];
98 
99  // We use the buffer to build an ip packet.
100  // To minimise unnecessary copying, we start with the payload
101  // and write it to the end of the buffer
102  memcpy( (buf + iplen + udplen), payload, payloadlen);
103 
104  // write udp header in front of the payload
105  udp_buf = (udphdr*) (buf + iplen);
106  udp_buf->source = htons(UDP->getSourcePort());
107  udp_buf->dest = htons(UDP->getDestinationPort());
108  udp_buf->len = htons(udplen + payloadlen);
109  udp_buf->check = 0;
110 
111  // Write udp pseudoheader in from of udp header
112  // this will be overwritten by ip header
113  pseudohdr = (udppseudohdr*) (buf + iplen - sizeof(struct udppseudohdr));
114  saddr = htonl(IP->getSrcAddress().getInt());
115  daddr = htonl(IP->getDestAddress().getInt());
116  pseudohdr->saddr = saddr;
117  pseudohdr->daddr = daddr;
118  pseudohdr->zero = 0;
119  pseudohdr->protocol = IPPROTO_UDP;
120  pseudohdr->lenght = udp_buf->len;
121 
122  // compute UDP checksum
123  udp_buf->check = cksum((uint16_t*) pseudohdr, sizeof(struct udppseudohdr) + udplen + payloadlen);
124 
125  // write ip header to begin of buffer
126  ip_buf = (iphdr*) buf;
127  ip_buf->version = 4; // IPv4
128  ip_buf->ihl = iplen / 4;
129  ip_buf->tos = IP->getDiffServCodePoint();
130  ip_buf->tot_len = htons(*length);
131  ip_buf->id = htons(IP->getIdentification());
132  ip_buf->frag_off = htons(IP_DF); // DF, no fragments
133  ip_buf->ttl = IP->getTimeToLive();
134  ip_buf->protocol = IPPROTO_UDP;
135  ip_buf->saddr = saddr;
136  ip_buf->daddr = daddr;
137  ip_buf->check = 0;
138  ip_buf->check = cksum((uint16_t*) ip_buf, iplen);
139 
140  delete IP;
141  delete UDP;
142  delete payloadMsg;
143  delete payload;
144 
145  return buf;
146 
147 parse_error:
148  delete IP;
149  delete UDP;
150  delete payloadMsg;
151  delete payload;
152  return NULL;
153 
154 }
155 
156 cPacket* TunOutDevice::decapsulate(char* buf,
157  uint32_t length,
158  sockaddr* addr,
159  socklen_t addrlen)
160 {
161  // Message starts with IP header
162  iphdr* ip_buf = (iphdr*) buf;
163  udphdr* udp_buf;
164  IPDatagram* IP = new IPDatagram;
165  UDPPacket* UDP = new UDPPacket;
166  cPacket* payload = 0;
167  unsigned int payloadLen, datagramlen;
168  unsigned int packetlen = ntohs(ip_buf->tot_len);
169 
170  // Parsing of IP header, sanity checks
171  if ( packetlen != length ) {
172  EV << "[TunOutDevice::decapsulate()]\n"
173  << " Dropping bogus packet, header says: length = " << packetlen << "\n"
174  << " but actual length = " << length
175  << endl;
176  goto parse_error;
177  }
178  if ( packetlen > mtu ) {
179  EV << "[TunOutDevice::decapsulate()]\n"
180  << " Dropping bogus packet, length = " << packetlen << "\n"
181  << " but mtu = " << mtu
182  << endl;
183  goto parse_error;
184  }
185  if ( ip_buf->version != 4 ) {
186  EV << "[TunOutDevice::decapsulate()]\n"
187  << " Dropping Packet: Packet is not IPv4"
188  << endl;
189  goto parse_error;
190  }
191  if ( ntohs(ip_buf->frag_off) & 0xBFFF ) { // mask DF bit
192  EV << "[TunOutDevice::decapsulate()]\n"
193  << " Dropping Packet: Can't handle fragmented packets"
194  << endl;
195  goto parse_error;
196  }
197  if ( ip_buf->protocol != IPPROTO_UDP ) { // FIXME: allow ICMP packets
198  EV << "[TunOutDevice::decapsulate()]\n"
199  << " Dropping Packet: Packet is not UDP"
200  << endl;
201  goto parse_error;
202  }
203  IP->setSrcAddress( IPAddress( ntohl(ip_buf->saddr) ));
204  IP->setDestAddress( IPAddress( ntohl(ip_buf->daddr) ));
205  IP->setTransportProtocol( ip_buf->protocol );
206  IP->setTimeToLive( ip_buf->ttl );
207  IP->setIdentification( ntohs(ip_buf->id) );
208  IP->setMoreFragments( false );
209  IP->setDontFragment( true );
210  IP->setFragmentOffset( 0 );
211  IP->setDiffServCodePoint( ip_buf->tos );
212  IP->setBitLength( ip_buf->ihl*32 );
213  // FIXME: check IP and UDP checksum...
214 
215  // Parse UDP header, sanity checks
216  udp_buf = (udphdr*)( ((uint32_t *)ip_buf) + ip_buf->ihl );
217  datagramlen = ntohs(udp_buf->len);
218  if ( (datagramlen != packetlen - ip_buf->ihl*4) ) {
219  EV << "[TunOutDevice::decapsulate()]\n"
220  << " Dropping Packet: Bogus UDP datagram length: len = " << datagramlen << "\n"
221  << " packetlen = " << packetlen << " ihl*4 " << ip_buf->ihl*4
222  << endl;
223  goto parse_error;
224  }
225  UDP->setSourcePort( ntohs( udp_buf->source ));
226  UDP->setDestinationPort( ntohs( udp_buf->dest ));
227  UDP->setByteLength( sizeof( struct udphdr ) );
228 
229  // parse payload
230  payloadLen = datagramlen - sizeof( struct udphdr );
231  payload = parser->decapsulatePayload( ((char*) udp_buf) + sizeof( struct udphdr ), payloadLen );
232  if (!payload) {
233  EV << "[TunOutDevice::decapsulate()]\n"
234  << " Parsing of Payload failed, dropping packet"
235  << endl;
236  goto parse_error;
237  }
238  // encapsulate messages
239  UDP->encapsulate( payload );
240  IP->encapsulate( UDP );
241 
242  delete[] buf;
243  delete addr;
244  return IP;
245 
246  // In case the parsing of the packet failed, free allocated memory
247 parse_error:
248  delete[] buf;
249  delete addr;
250  delete IP;
251  delete UDP;
252  return NULL;
253 }
254 
255 #else
256 
257 cPacket* TunOutDevice::decapsulate(char* buf,
258  uint32_t length,
259  sockaddr* addr,
260  socklen_t addrlen)
261 {
262  throw cRuntimeError("TunOutDevice::decapsulate(): Not supported on Windows/Mac OS yet");
263 }
264 
265 char* TunOutDevice::encapsulate(cPacket *msg,
266  unsigned int* length,
267  sockaddr** addr,
268  socklen_t* addrlen)
269 {
270  throw cRuntimeError("TunOutDevice::encapsulate(): Not supported on Windows/Mac OS yet");
271 }
272 
273 #endif