TunOutDevice.cc

Go to the documentation of this file.
00001 //
00002 // Copyright (C) 2006 Institut fuer Telematik, Universitaet Karlsruhe (TH)
00003 //
00004 // This program is free software; you can redistribute it and/or
00005 // modify it under the terms of the GNU General Public License
00006 // as published by the Free Software Foundation; either version 2
00007 // of the License, or (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with this program; if not, write to the Free Software
00016 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00017 //
00018 
00024 #include "IPDatagram_m.h"
00025 #include "UDPPacket.h"
00026 
00027 #include "TunOutDevice.h"
00028 
00029 Define_Module(TunOutDevice);
00030 
00031 #if not defined _WIN32 && not defined __APPLE__
00032 
00033 #include <netinet/ip.h>
00034 #include <netinet/udp.h>
00035 
00036 char* TunOutDevice::encapsulate(cPacket *msg,
00037                                 unsigned int* length,
00038                                 sockaddr** addr,
00039                                 socklen_t* addrlen)
00040 {
00041     *addr = 0;
00042     *addrlen = 0;
00043 
00044     struct udppseudohdr {
00045         uint32_t saddr;
00046         uint32_t daddr;
00047         uint8_t zero;
00048         uint8_t protocol;
00049         uint16_t lenght;
00050     }*pseudohdr;
00051 
00052     unsigned int payloadlen;
00053     static unsigned int iplen = 20; // we don't generate IP options
00054     static unsigned int udplen = 8;
00055     cPacket* payloadMsg = NULL;
00056     char* buf = NULL, *payload = NULL;
00057     uint32_t saddr, daddr;
00058     volatile iphdr* ip_buf;
00059     volatile udphdr* udp_buf;
00060 
00061     IPDatagram* IP = check_and_cast<IPDatagram*>(msg);
00062 
00063     // FIXME: Cast ICMP-Messages
00064     UDPPacket* UDP = dynamic_cast<UDPPacket*>(IP->decapsulate());
00065     if (!UDP) {
00066         EV << "[TunOutDevice::encapsulate()]\n"
00067            << "    Can't parse non-UDP packets (e.g. ICMP) (yet)"
00068            << endl;
00069         goto parse_error;
00070     }
00071 
00072     // TODO(?) Handle fragmented packets
00073     if( IP->getMoreFragments() ) {
00074         EV << "[TunOutDevice::encapsulate()]\n"
00075             << "    Can't parse fragmented packets"
00076             << endl;
00077         goto parse_error;
00078     }
00079     payloadMsg = UDP->decapsulate();
00080 
00081     // parse payload
00082     payload = parser->encapsulatePayload(payloadMsg, &payloadlen);
00083     if (!payload ) {
00084         EV << "[TunOutDevice::encapsulate()]\n"
00085            << "    Can't parse packet payload, dropping packet"
00086            << endl;
00087         goto parse_error;
00088     }
00089 
00090     *length = payloadlen + iplen + udplen;
00091     if( *length > mtu ) {
00092         EV << "[TunOutDevice::encapsulate()]\n"
00093            << "    Error: Packet too big! Size = " << *length << " MTU = " << mtu
00094            << endl;
00095         goto parse_error;
00096     }
00097 
00098     buf = new char[*length];
00099 
00100     // We use the buffer to build an ip packet.
00101     // To minimise unnecessary copying, we start with the payload
00102     // and write it to the end of the buffer
00103     memcpy( (buf + iplen + udplen), payload, payloadlen);
00104 
00105     // write udp header in front of the payload
00106     udp_buf = (udphdr*) (buf + iplen);
00107     udp_buf->source = htons(UDP->getSourcePort());
00108     udp_buf->dest = htons(UDP->getDestinationPort());
00109     udp_buf->len = htons(udplen + payloadlen);
00110     udp_buf->check = 0;
00111 
00112     // Write udp pseudoheader in from of udp header
00113     // this will be overwritten by ip header
00114     pseudohdr = (udppseudohdr*) (buf + iplen - sizeof(struct udppseudohdr));
00115     saddr = htonl(IP->getSrcAddress().getInt());
00116     daddr = htonl(IP->getDestAddress().getInt());
00117     pseudohdr->saddr = saddr;
00118     pseudohdr->daddr = daddr;
00119     pseudohdr->zero = 0;
00120     pseudohdr->protocol = IPPROTO_UDP;
00121     pseudohdr->lenght = udp_buf->len;
00122 
00123     // compute UDP checksum
00124     udp_buf->check = cksum((uint16_t*) pseudohdr, sizeof(struct udppseudohdr) + udplen + payloadlen);
00125 
00126     // write ip header to begin of buffer
00127     ip_buf = (iphdr*) buf;
00128     ip_buf->version = 4; // IPv4
00129     ip_buf->ihl = iplen / 4;
00130     ip_buf->tos = IP->getDiffServCodePoint();
00131     ip_buf->tot_len = htons(*length);
00132     ip_buf->id = htons(IP->getIdentification());
00133     ip_buf->frag_off = htons(IP_DF); // DF, no fragments
00134     ip_buf->ttl = IP->getTimeToLive();
00135     ip_buf->protocol = IPPROTO_UDP;
00136     ip_buf->saddr = saddr;
00137     ip_buf->daddr = daddr;
00138     ip_buf->check = 0;
00139     ip_buf->check = cksum((uint16_t*) ip_buf, iplen);
00140 
00141     delete IP;
00142     delete UDP;
00143     delete payloadMsg;
00144     delete payload;
00145 
00146     return buf;
00147 
00148 parse_error:
00149     delete IP;
00150     delete UDP;
00151     delete payloadMsg;
00152     delete payload;
00153     return NULL;
00154 
00155 }
00156 
00157 cPacket* TunOutDevice::decapsulate(char* buf,
00158                                     uint32_t length,
00159                                     sockaddr* addr,
00160                                     socklen_t addrlen)
00161 {
00162     // Message starts with IP header
00163     iphdr* ip_buf = (iphdr*) buf;
00164     udphdr* udp_buf;
00165     IPDatagram* IP = new IPDatagram;
00166     UDPPacket* UDP = new UDPPacket;
00167     cPacket* payload = 0;
00168     unsigned int payloadLen, datagramlen;
00169     unsigned int packetlen = ntohs(ip_buf->tot_len);
00170 
00171     // Parsing of IP header, sanity checks
00172     if (  packetlen != length ) {
00173         EV << "[TunOutDevice::decapsulate()]\n"
00174            << "    Dropping bogus packet, header says: length = " << packetlen << "\n"
00175            << "    but actual length = " << length
00176            << endl;
00177         goto parse_error;
00178     }
00179     if (  packetlen > mtu ) {
00180         EV << "[TunOutDevice::decapsulate()]\n"
00181            << "    Dropping bogus packet, length = " << packetlen << "\n"
00182            << "    but mtu = " << mtu
00183            << endl;
00184         goto parse_error;
00185     }
00186     if ( ip_buf->version != 4 ) {
00187         EV << "[TunOutDevice::decapsulate()]\n"
00188            << "    Dropping Packet: Packet is not IPv4"
00189            << endl;
00190         goto parse_error;
00191     }
00192     if ( ntohs(ip_buf->frag_off) & 0xBFFF ) { // mask DF bit
00193         EV << "[TunOutDevice::decapsulate()]\n"
00194            << "    Dropping Packet: Can't handle fragmented packets"
00195            << endl;
00196         goto parse_error;
00197     }
00198     if ( ip_buf->protocol != IPPROTO_UDP ) { // FIXME: allow ICMP packets
00199         EV << "[TunOutDevice::decapsulate()]\n"
00200            << "    Dropping Packet: Packet is not UDP"
00201            << endl;
00202         goto parse_error;
00203     }
00204     IP->setSrcAddress( IPAddress( ntohl(ip_buf->saddr) ));
00205     IP->setDestAddress( IPAddress( ntohl(ip_buf->daddr) ));
00206     IP->setTransportProtocol( ip_buf->protocol );
00207     IP->setTimeToLive( ip_buf->ttl );
00208     IP->setIdentification( ntohs(ip_buf->id) );
00209     IP->setMoreFragments( false );
00210     IP->setDontFragment( true );
00211     IP->setFragmentOffset( 0 );
00212     IP->setDiffServCodePoint( ip_buf->tos );
00213     IP->setBitLength( ip_buf->ihl*32 );
00214     // FIXME: check IP and UDP checksum...
00215 
00216     // Parse UDP header, sanity checks
00217     udp_buf = (udphdr*)( ((uint32_t *)ip_buf) + ip_buf->ihl );
00218     datagramlen = ntohs(udp_buf->len);
00219     if ( (datagramlen != packetlen - ip_buf->ihl*4) ) {
00220         EV << "[TunOutDevice::decapsulate()]\n"
00221            << "    Dropping Packet: Bogus UDP datagram length: len = " << datagramlen << "\n"
00222            << "    packetlen = " << packetlen << " ihl*4 " << ip_buf->ihl*4
00223            << endl;
00224         goto parse_error;
00225     }
00226     UDP->setSourcePort( ntohs( udp_buf->source ));
00227     UDP->setDestinationPort( ntohs( udp_buf->dest ));
00228     UDP->setByteLength( sizeof( struct udphdr ) );
00229 
00230     // parse payload
00231     payloadLen = datagramlen - sizeof( struct udphdr );
00232     payload = parser->decapsulatePayload( ((char*) udp_buf) + sizeof( struct udphdr ), payloadLen );
00233     if (!payload) {
00234         EV << "[TunOutDevice::decapsulate()]\n"
00235            << "    Parsing of Payload failed, dropping packet"
00236            << endl;
00237         goto parse_error;
00238     }
00239     // encapsulate messages
00240     UDP->encapsulate( payload );
00241     IP->encapsulate( UDP );
00242 
00243     delete[] buf;
00244     delete addr;
00245     return IP;
00246 
00247     // In case the parsing of the packet failed, free allocated memory
00248 parse_error:
00249     delete[] buf;
00250     delete addr;
00251     delete IP;
00252     delete UDP;
00253     return NULL;
00254 }
00255 
00256 #else
00257 
00258 cPacket* TunOutDevice::decapsulate(char* buf,
00259                                    uint32_t length,
00260                                    sockaddr* addr,
00261                                    socklen_t addrlen)
00262 {
00263     throw cRuntimeError("TunOutDevice::decapsulate(): Not supported on Windows/Mac OS yet");
00264 }
00265 
00266 char* TunOutDevice::encapsulate(cPacket *msg,
00267                                 unsigned int* length,
00268                                 sockaddr** addr,
00269                                 socklen_t* addrlen)
00270 {
00271     throw cRuntimeError("TunOutDevice::encapsulate(): Not supported on Windows/Mac OS yet");
00272 }
00273 
00274 #endif
Generated on Wed May 26 16:21:15 2010 for OverSim by  doxygen 1.6.3