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 483 2007-08-08 15:09:36Z remi $
 */

/*************************************************************************
 *  Copyright © 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, versions 2 or 3 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, see <http://www.gnu.org/licenses/>. *
 *************************************************************************/

#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)
{
      if (plen < sizeof (struct tcphdr))
            plen = sizeof (struct tcphdr);

      struct
      {
            struct tcphdr th;
            uint8_t payload[plen - sizeof (struct tcphdr)];
      } packet;

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

      return send_payload (fd, &packet, plen, ttl);
}


static ssize_t
parse_syn_resp (const void *data, size_t len, int *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, int *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)
{
      if (plen < sizeof (struct tcphdr))
            plen = sizeof (struct tcphdr);

      struct
      {
            struct tcphdr th;
            uint8_t payload[plen - sizeof (struct tcphdr)];
      } packet;

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

      return send_payload (fd, &packet, plen, ttl);
}


static ssize_t
parse_ack_resp (const void *data, size_t len, int *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, int *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