Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (GNU/Linux, *NIX, *BSD und Co) » IP-Header berechnen -> irgendwas is falsch

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
05.11.2008, 09:04 Uhr
~toski
Gast


hi, hab hier diese code um einen ip-header zu berechnen:


Code:
unsigned short ip_sum_calc(unsigned short len_ip_header, unsigned short buff[])
{
unsigned  short word16;
unsigned  long  sum=0;
unsigned  short i;

printf("In routine zur Pruefsummenberechnung");
    
    // make 16 bit words out of every two adjacent 8 bit words in the packet
    // and add them up
    for (i=0;i<len_ip_header;i=i+2){
        word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
        sum = sum + (unsigned long) word16;    
    }
    
    // take only 16 bits out of the 32 bit sum and add up the carries
    while (sum>>16)
      sum = (sum & 0xFFFF)+(sum >> 16);

    // one's complement the result
    sum = ~sum;
    
return ((unsigned short) sum);
}
//------schnippel
unsigned int headersize = sizeof(struct ip) + sizeof(struct udphdr);
unsigned int payload = 4096;
unsigned int packetsize = headersize + payload;
unsigned char packet[packetsize];
memset(packet,0,packetsize);

struct ip *iph     = (struct ip*) packet;
struct udphdr *udp = (struct udphdr *) packet + sizeof(struct ip);
//-------schnippel------
iph->ip_sum = ip_sum_calc ( iph->ip_len, (unsigned short*) packet);



jedesmal wenn ich ip_sum_calc aufrufe, krieg ich ein Segmentation fault runtime fehler. Ich versteh nicht ganz was falsch ist. Was ich mir an Beispielen gegoogelt hab entspricht eig. dem was ich hier habe (so zumindest meine wahrnehmung)...

sieht jemand was das problem ist? sind meine casts falsch?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
05.11.2008, 09:37 Uhr
ao

(Operator)


Welchen Wert hat iph->ip_len, wenn ip_sum_calc aufgerufen wird? packetsize, also 4096 plus ein bisschen? Dann denkt die calc-Funktion, sie hätte ein gut 4096 Elemente langes unsigned-short-Array zu bearbeiten, also etwas über 8 K Speicher. In Wahrheit sinds nur 4 K, und danach greift die Funktion ins Klo.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
06.11.2008, 13:16 Uhr
~toski
Gast


hm....ok.

ich versteh jetz aber nicht wie ich das problem gelöst kriege ???
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
06.11.2008, 14:58 Uhr
ao

(Operator)


Moment, ich korrigiere mich.

Das mit der Größe ist nur der eine Fehler. Auch in der For-Schleife passiert irgendein Strunx, du bist irgendwie mit short und char durcheinander.

C++:
    // make 16 bit words out of every two adjacent 8 bit words in the packet
    // and add them up
    for (i=0;i<len_ip_header;i=i+2){
        word16 =((buff[i]<<8)&0xFF00)+(buff[i+1]&0xFF);
        sum = sum + (unsigned long) word16;    
    }


Denk da noch mal in Ruhe drüber nach und berücksichtige, das buff ein unsigned short-Array ist, kein Byte-Array. Du tauschst eben nicht (wie im Kommentar behauptet) die beiden Bytes eines ushort, sondern du holst dir zwei benachbarte ushorts und arbeitest mit denen, aber dadurch kriegst du "nur" ein falsches Ergebnis.

Im Schleifenkopf inkrementierst du i um 2 (Anzahl Durchläufe ist also len_ip_header / 2), aber jeder Durchlauf addressiert 4 Bytes Speicher, dadurch überstreicht die ganze Schleife den doppelten Speicherbereich - das führt zu dem SegFault.

Glaube ich. Ich hab grad keine Zeit, tiefer einzutauchen.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
06.11.2008, 22:44 Uhr
0xdeadbeef
Gott
(Operator)


Also, wenn ich richtig verstehe, was du hier willst, muss erstens der Aufruf

C++:
iph->ip_sum = ip_sum_calc ( iph->ip_hl, (unsigned short*) packet);


heißen, weil's hier ja nur um den Header geht. Außerdem bezeichnet der die Länge in Byte. Das heißt nicht, dass die Verarbeitung als unsigned short (bzw. besser uint16_t aus <stdint.h> eine schlechte Idee ist, aber deine Bytes sind bereits zu 16-bit-Wörtern verschmolzen. Wichtig ist, dass du hier auf den Bytesex achtest, aber zum Glück gibt's dafür ja ntohs:

C++:
    for (i = 0; i < len_ip_header / 2; ++i) {
        sum += ntohs(buff[i]);
    }


Vergiss nicht, dafür <arpa/inet.h> zu #includen.

Das ist jedenfalls das beste, was mich meine Kristallkugel sehen lässt.

Nachtrag: Es wäre eventuell erwägenswert, die Länge des Arrays, wie die Funktion es sieht, zu übergeben, um ein konsistentes Interface zu bieten. Das bedeutet, entweder

C++:
uint16_t ip_sum_calc(size_t len_ip_header, uint16_t const buff[]) {
  size_t i;

  for (i = 0; i < len_ip_header; ++i) {
    sum += ntohs(buff[i]);
  }

  // ...
}

// ...

iph->ip_sum = ip_sum_calc (iph->ip_hl / 2, (unsigned short const*) packet);


oder

C++:
uint16_t ip_sum_calc(size_t len_ip_header, uint8_t const buff[]) {
  uint16_t const *buf_work = (uint16_t const *) buff;
  size_t i;

  for (i = 0; i < len_ip_header / 2; ++i) {
    sum += ntohs(buf_work[i]);
  }

  // ...
}

// ...

iph->ip_sum = ip_sum_calc (iph->ip_hl, packet);


--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 06.11.2008 um 22:51 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
08.11.2008, 12:53 Uhr
~toski
Gast


hm ok, hab es jetzt mal so gemacht und mir von woandes eine neue checksum routine kopiert, wenn ich jetzt zum sendto()-Befehl komme, krieg ich die Meldung das ich invalid argument angegeben haben.
Ist das jetzt noch die Headerprüfsumme oder is da noch was anderes falsch ?

Bin mir nicht sicher ob ich beim Aufruf des send-to die parameter richtig mitgebe. Kann ich als Destination-Adress die information aus dem header nehmen oder sind die typen inkompatibel?


Code:
#define __USE_BSD    /* use bsd'ish ip header */
#include <sys/socket.h>    /* these headers are for a Linux system, but */
#include <netinet/ip.h>
#include <netinet/udp.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned short in_cksum(unsigned short *ptr, int nbytes)
{
  register long sum =0;
  u_short oddbyte = 0;
  
  while(nbytes > 1)
  {
    sum += *ptr++;
    nbytes -=2;
  }
  
  if(nbytes == 1)
  {
     *((u_char *) &oddbyte) = *(u_char*) ptr;
     sum += oddbyte;
  }
  
  sum = (sum>>16) + (sum & 0xffff);
  sum += (sum>>16);
  
  return (u_short)~sum;
}


int main(int argc, char **argv)
{

  /* Aktuelle Nutzer Root bzw. Rootrechte vorhanden */
  int uid = geteuid();
  if ( uid != 0)
  {
      printf("Benoetigt Root-Rechte! Aktuelle ID: %i", uid);
      exit(1);
  }
  
  

unsigned int headersize = sizeof(struct ip) + sizeof(struct udphdr);
unsigned int payload = 4096;
unsigned int packetsize = headersize + payload;
unsigned char packet[packetsize];
memset(packet,0,packetsize);

struct ip *iph     = (struct ip*) packet;
struct udphdr *udp = (struct udphdr *) packet + sizeof(struct ip);



int rawsock=0;
if ((rawsock = socket(AF_INET, SOCK_RAW, IPPROTO_UDP)) < 0)
{
     perror("Socketerzeugung ist in die Hose gegangen!");
     exit(1);
}


/* Eigenen IP-Header verwenden, Kernel-Header unterdrücken */
int on=1;
if (setsockopt(rawsock, IPPROTO_IP, IP_HDRINCL, (const char* )&on, sizeof(on)) < 0 )
{
   perror("IP_HDRINCL fehlgeschlagen!\n");
   exit(1);
}

/* IP Header zusammenbauen */
iph->ip_v                    = 4; //IPv4
iph->ip_hl                = 5;
iph->ip_tos               = 0x0;
iph->ip_len              = htons(packetsize); /* Groesse das Paketes */
iph->ip_ttl            = 255;
iph->ip_sum             = 0;    //Berechnung erfolgt weiter unten
iph->ip_p                 = IPPROTO_UDP;
iph->ip_src.s_addr     = inet_addr("192.168.2.103");
iph->ip_dst.s_addr     = inet_addr("127.0.0.1");
iph->ip_id             = htons(random());

/* UDP Header zusammenbauen */
udp->uh_sport            = 1234;
udp->uh_dport            = 1235;
udp->uh_ulen            = sizeof(struct udphdr) + payload;
udp->uh_sum            = 0;

//printf("Checksumme berechnen, Headersize \n");
iph->ip_sum = in_cksum((unsigned short*) &iph, sizeof(struct ip));
printf("Errechnete Checksumme: %i\n", iph->ip_sum);


printf("Versenden\n");
if (sendto(rawsock, packet, packetsize, 0, (struct sockaddr*) &(iph->ip_dst.s_addr),
                                             sizeof(struct sockaddr_in)) < 0 )
    perror("Da is was Fehlgeschlagen");
    
close(rawsock);


return 0;
}

 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (GNU/Linux, *NIX, *BSD und Co) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: