📄 mod-tcpconn.c
字号:
/* Copyright (c) 2006, 2007 Dmitry Butskoy <buc@citadel.stu.neva.ru> License: GPL v2 or any later See COPYING for the status of this software.*/#include <stdlib.h>#include <unistd.h>#include <sys/socket.h>#include <sys/poll.h>#include <netinet/icmp6.h>#include <netinet/ip_icmp.h>#include <netinet/in.h>#include <netinet/ip.h>#include <netinet/ip6.h>#include <netinet/tcp.h>#include <errno.h>#include "traceroute.h"static sockaddr_any dest_addr = {{ 0, }, };static int icmp_sk = -1;static int tcp_init (const sockaddr_any *dest, unsigned int port_seq, size_t *packet_len_p) { int af = dest->sa.sa_family; dest_addr = *dest; dest_addr.sin.sin_port = htons (DEF_TCP_PORT); if (port_seq) dest_addr.sin.sin_port = htons (port_seq); /* Currently an ICMP socket is the only way to obtain the needed info... */ icmp_sk = socket (af, SOCK_RAW, (af == AF_INET) ? IPPROTO_ICMP : IPPROTO_ICMPV6); if (icmp_sk < 0) error ("socket"); /* icmp_sk not need full tune_socket() here, just a receiving one */ bind_socket (icmp_sk); use_timestamp (icmp_sk); use_recv_ttl (icmp_sk); add_poll (icmp_sk, POLLIN); return 0;}static void tcp_send_probe (probe *pb, int ttl) { int sk; int af = dest_addr.sa.sa_family; sockaddr_any addr; socklen_t length = sizeof (addr); sk = socket (af, SOCK_STREAM, 0); if (sk < 0) error ("socket"); tune_socket (sk); /* common stuff */ set_ttl (sk, ttl); pb->send_time = get_time (); if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0) { if (errno != EINPROGRESS) error ("connect"); } if (getsockname (sk, &addr.sa, &length) < 0) error ("getsockname"); pb->seq = addr.sin.sin_port; /* both ipv4/ipv6 */ pb->sk = sk; add_poll (sk, POLLERR | POLLHUP | POLLOUT); return;}static probe *tcp_check_reply (int sk, int err, sockaddr_any *from, char *buf, size_t len) { int af = dest_addr.sa.sa_family; int type, code, info; probe *pb; struct tcphdr *tcp; if (len < sizeof (struct icmphdr)) return NULL; if (af == AF_INET) { struct icmp *icmp = (struct icmp *) buf; struct iphdr *ip; int hlen; type = icmp->icmp_type; code = icmp->icmp_code; info = icmp->icmp_void; if (type != ICMP_TIME_EXCEEDED && type != ICMP_DEST_UNREACH) return NULL; if (len < sizeof (struct icmphdr) + sizeof (struct iphdr) + 8) /* `8' - rfc1122: 3.2.2 */ return NULL; ip = (struct iphdr *) (((char *)icmp) + sizeof(struct icmphdr)); hlen = ip->ihl << 2; if (len < sizeof (struct icmphdr) + hlen + 8) return NULL; if (ip->protocol != IPPROTO_TCP) return NULL; tcp = (struct tcphdr *) (((char *) ip) + hlen); } else { /* AF_INET6 */ struct icmp6_hdr *icmp6 = (struct icmp6_hdr *) buf; struct ip6_hdr *ip6; type = icmp6->icmp6_type; code = icmp6->icmp6_code; info = icmp6->icmp6_mtu; if (type != ICMP6_TIME_EXCEEDED && type != ICMP6_DST_UNREACH && type != ICMP6_PACKET_TOO_BIG ) return NULL; if (len < sizeof(struct icmp6_hdr) + sizeof(struct ip6_hdr) + 8) return NULL; ip6 = (struct ip6_hdr *) (icmp6 + 1); if (ip6->ip6_nxt != IPPROTO_TCP) return NULL; tcp = (struct tcphdr *) (ip6 + 1); } if (tcp->dest != dest_addr.sin.sin_port) return NULL; pb = probe_by_seq (tcp->source); if (!pb) return NULL; /* here only, high level has no data to do this */ parse_icmp_res (pb, type, code, info); return pb;}static void tcp_recv_probe (int sk, int revents) { if (sk != icmp_sk) { /* a tcp socket */ probe *pb; pb = probe_by_sk (sk); if (!pb) { del_poll (sk); return; } /* do connect() again and check errno, regardless of revents */ if (connect (sk, &dest_addr.sa, sizeof (dest_addr)) < 0) { if (errno != EISCONN && errno != ECONNREFUSED) return; /* ICMP say more */ } /* we have reached the dest host (either connected or refused) */ memcpy (&pb->res, &dest_addr, sizeof (pb->res)); pb->final = 1; pb->recv_time = get_time (); probe_done (pb); return; } /* ICMP stuff */ if (!(revents & POLLIN)) return; recv_reply (icmp_sk, 0, tcp_check_reply);}static void tcp_expire_probe (probe *pb) { probe_done (pb);}static tr_module tcp_ops = { .name = "tcpconn", .init = tcp_init, .send_probe = tcp_send_probe, .recv_probe = tcp_recv_probe, .expire_probe = tcp_expire_probe, .user = 0,};TR_MODULE (tcp_ops);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -