0
votes

I recently started writing a packet sniffer using libpcap & linux specific libraries and headers like netinet/tcp.h. The problem is: When I get the tcp header using TH_OFF(tcp)*4, its value is frequently less than 20 bytes. Ok, I know, it's malformed, but Wireshark is displaying other value(20<). The same happens with the flags.

Here is the code:

struct nread_tcp {
    u_short th_sport; /* source port            */
    u_short th_dport; /* destination port       */
    u_short th_seq;   /* sequence number        */
    u_short th_ack;   /* acknowledgement number */
#if BYTE_ORDER == LITTLE_ENDIAN
    u_int th_x2:4,    /* (unused)    */
    th_off:4;         /* data offset */
#endif
#if BYTE_ORDER == BIG_ENDIAN
    u_int th_off:4,   /* data offset */
    th_x2:4;          /* (unused)    */
#endif
    u_char th_flags;
#define TH_FIN      0x01
#define TH_SYN      0x02
#define TH_RST      0x04
#define TH_PUSH     0x08
#define TH_ACK      0x10
#define TH_URG      0x20
#define TH_ECE      0x40
#define TH_CWR      0x80

#define TH_NS       0x100
#define TH_RS       0xE00

    u_short th_win; /* window */
    u_short th_sum; /* checksum */
    u_short th_urp; /* urgent pointer */
u_char  th_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
};

const struct nread_tcp* tcp = (struct nread_tcp*)(pachet + sizeof(struct ether_header) + sizeof(struct crt_ip));

...
int hlen = TH_OFF(tcp)*4;

char * tmp = new char[strlen("000000000000")+1];
    strcpy(tmp,"000000000000");

    if (tcp->th_flags & TH_NS){
        tmp[3] = '1';
        }
    else
        tmp[3] = '0';


    if (tcp->th_flags & TH_ECE){
        tmp[4] = '1';
        }
    else
        tmp[4] = '0';

    if (tcp->th_flags & TH_CWR){
        tmp[5] = '1';
        }
    else
        tmp[5] = '0';

    if (tcp->th_flags & TH_URG){
        tmp[6] = '1';
        }
    else
        tmp[6] = '0';

    if (tcp->th_flags & TH_ACK){
        tmp[7] = '1';
        }
    else
        tmp[7] = '0';

    if (tcp->th_flags & TH_PUSH){
        tmp[8] = '1';
        }
    else
        tmp[8] = '0';

    if (tcp->th_flags & TH_RST){
        tmp[9] = '1';
        }
    else
        tmp[9] = '0';

    if (tcp->th_flags & TH_SYN){
        tmp[10] = '1';
        }
    else
        tmp[10] = '0';

    if (tcp->th_flags & TH_FIN){
        tmp[11] = '1';
        }
    else
        tmp[11] = '0';

I've googled it quite a bit and haven't find something useful. Maybe it's another begginer's error but i can't figure it out. Thanks in advance.


Once again, thanks for the tips/ideas.

All pcap handling functions including handling the link-layer headers are correct. My app is written in Qt 4.7.4. Let me give you some more info about my logic. Maybe Im using pointers that are not pointing correctly. I wish to emphasize the fact that tcp is the only protocol with this issue. The others that Im analyzing in detail are Ethernet frame header, IP header, UDP header, ARP/RARP header and ICMP header. As for the logic, it goes like this: I have a thread witch listens
-pcap_loop(captureHandler,-1,packetHandler,(unsigned char*)dumpfile); The packetHandler is on a separate .cpp named "engine.cpp" In that .cpp I have the packet interpreter witch, accordingly to the protocol type, instantiates the right class(tcpPacketHandler for tcp protocol). My tcp struct is declared in engine.h (not the tcpPacketHandler header). The tcp struct is the one posted in my initial question. The tcpPacketHandler constructor looks like this:

tcpPacketHandler::tcpPacketHandler(u_char *arg, const pcap_pkthdr * header,const u_char * pachet)
{

    (void)arg;
    (void)header;

    const struct nread_tcp* tcp = (struct nread_tcp*)(pachet + sizeof(struct ether_header) + sizeof(struct crt_ip));
    //fprintf(stdout,"\nSEQUENCE NUMBER %u \nACK %u \nWINDOW %u\nURGENT POINTER %u\n", tcp->th_seq, tcp->th_ack, tcp->th_win,tcp->th_urp);

    //qDebug() <<sizeof(struct ether_header)<< "  "<< sizeof(struct crt_ip);
    this->seqNr                 = ntohs(tcp->th_seq);
    this->ackNr                 = ntohs(tcp->th_ack);
    this->window                = ntohs(tcp->th_win);
    this->urgentPointer         = ntohs(tcp->th_urp);
    this->portSursa             = ntohs(tcp->th_sport);
    this->portDestinatie        = ntohs(tcp->th_dport);
    this->checksum              = ntohs(tcp->th_sum);


    char * tmp = new char[strlen("000000000000")+1];
    strcpy(tmp,"000000000000");

    if (tcp->th_flags & TH_NS){
        tmp[3] = '1';
        }
    else
        tmp[3] = '0';


    if (tcp->th_flags & TH_ECE){
        tmp[4] = '1';
        }
    else
        tmp[4] = '0';

    if (tcp->th_flags & TH_CWR){
        tmp[5] = '1';
        }
    else
        tmp[5] = '0';

    if (tcp->th_flags & TH_URG){
        tmp[6] = '1';
        }
    else
        tmp[6] = '0';

    if (tcp->th_flags & TH_ACK){
        tmp[7] = '1';
        }
    else
        tmp[7] = '0';

    if (tcp->th_flags & TH_PUSH){
        tmp[8] = '1';
        }
    else
        tmp[8] = '0';

    if (tcp->th_flags & TH_RST){
        tmp[9] = '1';
        }
    else
        tmp[9] = '0';

    if (tcp->th_flags & TH_SYN){
        tmp[10] = '1';
        }
    else
        tmp[10] = '0';

    if (tcp->th_flags & TH_FIN){
        tmp[11] = '1';
        }
    else
        tmp[11] = '0';

    this->hdrLen = TH_OFF(tcp)*4;
   // qDebug() << this->hdrLen;

    this->flags = new char[13];
    strcpy(this->flags,tmp);

    if(tmp)
    {
        delete [] tmp;
        tmp = NULL;
    }


}

All the tcp header fields are displayed correctly until I hit the "data offset field"

#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)

From this point on the remainder of the tcp header data does not correspond with the Wireshark result (Data offset, Flags and Payload).

Maybe the problem is that the nread_tcp struct is declared in a file shared by multiple packets and the pointer goes wrong when capturing lots of packets in a short interval. I really have no clue. Every thing that I found on Google uses this struct, but I dont know whats the problem in my code. And as a secondarry question: can the packetHandler function (from pcap_loop function) be declared as member of a class? (because I noticed it has no type and when I tried to make it a class member the compiler thrown me an error).

Thanks in advance.

2

2 Answers

0
votes

There is no data offset field in the TCP header after the urgent pointer; the TCP header has options after the urgent pointer. Instead, remove the

#if BYTE_ORDER == LITTLE_ENDIAN
    u_int th_x2:4,    /* (unused)    */
    th_off:4;         /* data offset */
#endif
#if BYTE_ORDER == BIG_ENDIAN
    u_int th_off:4,   /* data offset */
    th_x2:4;          /* (unused)    */
#endif

from your structure and move

u_char  th_offx2;               /* data offset, rsvd */
#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)

up to replace it, so the structure looks like

struct nread_tcp {
    u_short th_sport; /* source port            */
    u_short th_dport; /* destination port       */
    u_short th_seq;   /* sequence number        */
    u_short th_ack;   /* acknowledgement number */
    u_char  th_offx2; /* data offset, rsvd */
#define TH_OFF(th)      (((th)->th_offx2 & 0xf0) >> 4)
    u_char  th_flags;
#define TH_FIN      0x01
#define TH_SYN      0x02
#define TH_RST      0x04
#define TH_PUSH     0x08
#define TH_ACK      0x10
#define TH_URG      0x20
#define TH_ECE      0x40
#define TH_CWR      0x80

#define TH_NS       0x100
#define TH_RS       0xE00

    u_short th_win; /* window */
    u_short th_sum; /* checksum */
    u_short th_urp; /* urgent pointer */
};

and recompile your program, and see whether that works.

0
votes

Here's what worked for me.

u_short th_seq;   /* sequence number        */
u_short th_ack;   /* acknowledgement number */

Changed to:

u_int th_seq;   /* sequence number        */
u_int th_ack;   /* acknowledgement number */