Logo Search packages:      
Sourcecode: ndisc6 version File versions  Download package

trace-tcp.c

/*
 * trace-tcp.c - TCP support for IPv6 traceroute tool
 * $Id: trace-tcp.c 305 2006-09-27 17:44:50Z remi $
 */

/***********************************************************************
 *  Copyright (C) 2005-2006 RĂ©mi Denis-Courmont.                       *
 *  This program is free software; you can redistribute and/or modify  *
 *  it under the terms of the GNU General Public License as published  *
 *  by the Free Software Foundation; version 2 of the license.         *
 *                                                                     *
 *  This program is distributed in the hope that it will be useful,    *
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
 *  See the GNU General Public License for more details.               *
 *                                                                     *
 *  You should have received a copy of the GNU General Public License  *
 *  along with this program; if not, you can get it from:              *
 *  http://www.gnu.org/copyleft/gpl.html                               *
 ***********************************************************************/

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#undef _GNU_SOURCE
#define _BSD_SOURCE 1

#include <string.h>
#include <inttypes.h>
#include <stdbool.h>

#include <sys/types.h>
#include <unistd.h> // getpid()
#include <sys/socket.h> // SOCK_STREAM
#include <netinet/in.h>
#include <netinet/tcp.h>

#include "traceroute.h"

#define TCP_WINDOW 4096

#ifndef TH_ECE
# define TH_ECE 0x40
# define TH_CWR 0x80
#endif

/* TCP/SYN probes */
static ssize_t
send_syn_probe (int fd, unsigned ttl, unsigned n, size_t plen, uint16_t port)
{
      struct tcphdr th;

      memset (&th, 0, sizeof (th));
      th.th_sport = sport;
      th.th_dport = port;
      th.th_seq = htonl ((ttl << 24) | (n << 16) | getpid ());
      th.th_off = sizeof (th) / 4;
      th.th_flags = TH_SYN | (ecn ? (TH_ECE | TH_CWR) : 0);
      th.th_win = htons (TCP_WINDOW);
      (void)plen; // FIXME

      return send_payload (fd, &th, sizeof (th));
}


static ssize_t
parse_syn_resp (const void *data, size_t len, unsigned *ttl, unsigned *n,
                uint16_t port)
{
      const struct tcphdr *pth = (const struct tcphdr *)data;
      uint32_t seq;

      if ((len < sizeof (*pth))
       || (pth->th_dport != sport)
       || (pth->th_sport != port)
       || ((pth->th_flags & TH_ACK) == 0)
       || (((pth->th_flags & TH_SYN) != 0) == ((pth->th_flags & TH_RST) != 0))
       || (pth->th_off < (sizeof (*pth) / 4)))
            return -1;

      seq = ntohl (pth->th_ack) - 1;
      if ((seq & 0xffff) != (unsigned)getpid ())
            return -1;

      *ttl = seq >> 24;
      *n = (seq >> 16) & 0xff;
      return 1 + ((pth->th_flags & TH_SYN) == TH_SYN);
}


static ssize_t
parse_syn_error (const void *data, size_t len, unsigned *ttl, unsigned *n,
                 uint16_t port)
{
      const struct tcphdr *pth = (const struct tcphdr *)data;
      uint32_t seq;

      if ((len < 8)
       || (pth->th_sport != sport)
       || (pth->th_dport != port))
            return -1;

      seq = ntohl (pth->th_seq);
      if ((seq & 0xffff) != (unsigned)getpid ())
            return -1;

      *ttl = seq >> 24;
      *n = (seq >> 16) & 0xff;
      return 0;
}


const tracetype syn_type =
      { SOCK_STREAM, IPPROTO_TCP, 16,
        send_syn_probe, parse_syn_resp, parse_syn_error };


/* TCP/ACK probes */
static ssize_t
send_ack_probe (int fd, unsigned ttl, unsigned n, size_t plen, uint16_t port)
{
      struct tcphdr th;

      memset (&th, 0, sizeof (th));
      th.th_sport = sport;
      th.th_dport = port;
      th.th_ack = htonl ((ttl << 24) | (n << 16) | getpid ());
      th.th_off = sizeof (th) / 4;
      th.th_flags = TH_ACK;
      th.th_win = htons (TCP_WINDOW);
      (void)plen; // FIXME

      return send_payload (fd, &th, sizeof (th));
}


static ssize_t
parse_ack_resp (const void *data, size_t len, unsigned *ttl, unsigned *n,
                uint16_t port)
{
      const struct tcphdr *pth = (const struct tcphdr *)data;
      uint32_t seq;

      if ((len < sizeof (*pth))
       || (pth->th_dport != sport)
       || (pth->th_sport != port)
       || (pth->th_flags & TH_SYN)
       || (pth->th_flags & TH_ACK)
       || ((pth->th_flags & TH_RST) == 0)
       || (pth->th_off < (sizeof (*pth) / 4)))
            return -1;

      seq = ntohl (pth->th_seq);
      if ((seq & 0xffff) != (unsigned)getpid ())
            return -1;

      *ttl = seq >> 24;
      *n = (seq >> 16) & 0xff;
      return 0;
}


static ssize_t
parse_ack_error (const void *data, size_t len, unsigned *ttl, unsigned *n,
                 uint16_t port)
{
      const struct tcphdr *pth = (const struct tcphdr *)data;
      uint32_t seq;

      if ((len < 8)
       || (pth->th_sport != sport)
       || (pth->th_dport != port))
            return -1;

      seq = ntohl (pth->th_ack);
      if ((seq & 0xffff) != (unsigned)getpid ())
            return -1;

      *ttl = seq >> 24;
      *n = (seq >> 16) & 0xff;
      return 0;
}


const tracetype ack_type =
      { SOCK_STREAM, IPPROTO_TCP, 16,
        send_ack_probe, parse_ack_resp, parse_ack_error };


Generated by  Doxygen 1.6.0   Back to index