⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 traceroute.c

📁 linux下traceroute的实现
💻 C
📖 第 1 页 / 共 3 页
字号:
						rtbuf, rtbuf_len) < 0		)  error ("setsockopt IPV6_RTHDR");	    }	}	bind_socket (sk);	if (af == AF_INET) {	    i = dontfrag ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT;	    if (setsockopt (sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0 &&		(!dontfrag || (i = IP_PMTUDISC_DO,		 setsockopt (sk, SOL_IP, IP_MTU_DISCOVER, &i, sizeof(i)) < 0))	    )  error ("setsockopt IP_MTU_DISCOVER");	    if (tos) {		i = tos;		if (setsockopt (sk, SOL_IP, IP_TOS, &i, sizeof (i)) < 0)			error ("setsockopt IP_TOS");	    }	}	else if (af == AF_INET6) {	    i = dontfrag ? IPV6_PMTUDISC_PROBE : IPV6_PMTUDISC_DONT;	    if (setsockopt (sk, SOL_IPV6, IPV6_MTU_DISCOVER,&i,sizeof(i)) < 0 &&		(!dontfrag || (i = IPV6_PMTUDISC_DO,		 setsockopt (sk, SOL_IPV6, IPV6_MTU_DISCOVER,&i,sizeof(i)) < 0))	    )  error ("setsockopt IPV6_MTU_DISCOVER");	    if (flow_label) {		struct in6_flowlabel_req flr;		memset (&flr, 0, sizeof (flr));		flr.flr_label = htonl (flow_label & 0x000fffff);                flr.flr_action = IPV6_FL_A_GET;                flr.flr_flags = IPV6_FL_F_CREATE;                flr.flr_share = IPV6_FL_S_EXCL;		memcpy (&flr.flr_dst, &dst_addr.sin6.sin6_addr,						    sizeof (flr.flr_dst));		if (setsockopt (sk, IPPROTO_IPV6, IPV6_FLOWLABEL_MGR,						    &flr, sizeof (flr)) < 0		)  error ("setsockopt IPV6_FLOWLABEL_MGR");	    }	    if (tos || flow_label) {		i = 1;		if (setsockopt (sk, IPPROTO_IPV6, IPV6_FLOWINFO_SEND,							&i, sizeof (i)) < 0		)  error ("setsockopt IPV6_FLOWINFO_SEND");	    }	}  	if (noroute) {	    i = noroute;	    if (setsockopt (sk, SOL_SOCKET, SO_DONTROUTE, &i, sizeof (i)) < 0)		    error ("setsockopt SO_DONTROUTE");	}	use_timestamp (sk);	use_recv_ttl (sk);	fcntl (sk, F_SETFL, O_NONBLOCK);	return;}void parse_icmp_res (probe *pb, int type, int code, int info) {	char *str = NULL;	char buf[sizeof (pb->err_str)];	if (af == AF_INET) {	    if (type == ICMP_TIME_EXCEEDED) {		if (code == ICMP_EXC_TTL)			return;	    }	    else if (type == ICMP_DEST_UNREACH) {		switch (code) {		    case ICMP_UNREACH_NET:		    case ICMP_UNREACH_NET_UNKNOWN:		    case ICMP_UNREACH_ISOLATED:		    case ICMP_UNREACH_TOSNET:			    str = "!N";			    break;		    case ICMP_UNREACH_HOST:		    case ICMP_UNREACH_HOST_UNKNOWN:		    case ICMP_UNREACH_TOSHOST:			    str = "!H";			    break;		    case ICMP_UNREACH_NET_PROHIB:		    case ICMP_UNREACH_HOST_PROHIB:		    case ICMP_UNREACH_FILTER_PROHIB:			    str = "!X";			    break;		    case ICMP_UNREACH_PORT:			    /*  dest host is reached   */			    str = "";			    break;		    case ICMP_UNREACH_PROTOCOL:			    str = "!P";			    break;		    case ICMP_UNREACH_NEEDFRAG:			    snprintf (buf, sizeof (buf), "!F-%d", info);			    str = buf;			    break;		    case ICMP_UNREACH_SRCFAIL:			    str = "!S";			    break;		    case ICMP_UNREACH_HOST_PRECEDENCE:			    str = "!V";			    break;		    case ICMP_UNREACH_PRECEDENCE_CUTOFF:			    str = "!C";			    break;		    default:			    snprintf (buf, sizeof (buf), "!<%u>", code);			    str = buf;			    break;		}	    }	}	else if (af == AF_INET6) {	    if (type == ICMP6_TIME_EXCEEDED) {		if (code == ICMP6_TIME_EXCEED_TRANSIT)			return;	    }	    else if (type == ICMP6_DST_UNREACH) {		switch (code) {		    case ICMP6_DST_UNREACH_NOROUTE:			    str = "!N";			    break;		    case ICMP6_DST_UNREACH_BEYONDSCOPE:		    case ICMP6_DST_UNREACH_ADDR:			    str = "!H";			    break;		    case ICMP6_DST_UNREACH_ADMIN:			    str = "!X";			    break;		    case ICMP6_DST_UNREACH_NOPORT:			    /*  dest host is reached   */			    str = "";			    break;		    default:			    snprintf (buf, sizeof (buf), "!<%u>", code);			    str = buf;			    break;		}	    }	    else if (type == ICMP6_PACKET_TOO_BIG) {		snprintf (buf, sizeof (buf), "!F-%d", info);		str = buf;	    }	}	if (!str) {	    snprintf (buf, sizeof (buf), "!<%u-%u>", type, code);	    str = buf;	}	if (*str) {	    strncpy (pb->err_str, str, sizeof (pb->err_str));	    pb->err_str[sizeof (pb->err_str) - 1] = '\0';	}	pb->final = 1;	return;}void probe_done (probe *pb) {	if (pb->sk) {	    del_poll (pb->sk);	    close (pb->sk);	    pb->sk = 0;	}	pb->seq = 0;	pb->done = 1;}void recv_reply (int sk, int err, check_reply_t check_reply) {	struct msghdr msg;	sockaddr_any from;	struct iovec iov;	int n;	probe *pb;	char buf[1280];		/*  min mtu for ipv6 ( >= 576 for ipv4)  */	char *bufp = buf;	char control[1024];	struct cmsghdr *cm;	struct sock_extended_err *ee = NULL;	memset (&msg, 0, sizeof (msg));	msg.msg_name = &from;	msg.msg_namelen = sizeof (from);	msg.msg_control = control;	msg.msg_controllen = sizeof (control);	iov.iov_base = buf;	iov.iov_len = sizeof (buf);	msg.msg_iov = &iov;	msg.msg_iovlen = 1;	n = recvmsg (sk, &msg, err ? MSG_ERRQUEUE : 0);	if (n < 0)  return;	/*  when not MSG_ERRQUEUE, AF_INET returns full ipv4 header	    on raw sockets...	*/	if (!err &&	    af == AF_INET &&	    /*  XXX: Assume that the presence of an extra header means		that it is not a raw socket...	    */	    ops->header_len == 0	) {	    struct iphdr *ip = (struct iphdr *) bufp;	    int hlen;	    if (n < sizeof (struct iphdr))  return;	    hlen = ip->ihl << 2;	    if (n < hlen)  return;	    bufp += hlen;	    n -= hlen;	}	pb = check_reply (sk, err, &from, bufp, n);	if (!pb)  return;	if (!err)	    memcpy (&pb->res, &from, sizeof (pb->res));	/*  Parse CMSG stuff   */	for (cm = CMSG_FIRSTHDR (&msg); cm; cm = CMSG_NXTHDR (&msg, cm)) {	    if (cm->cmsg_level == SOL_SOCKET) {		if (cm->cmsg_type == SO_TIMESTAMP) {		    struct timeval *tv = (struct timeval *) CMSG_DATA (cm);		    pb->recv_time = tv->tv_sec + tv->tv_usec / 1000000.;		}	    }	    else if (cm->cmsg_level == SOL_IP) {		if (cm->cmsg_type == IP_TTL)			pb->recv_ttl = *((int *) CMSG_DATA (cm));		else if (cm->cmsg_type == IP_RECVERR) {		    ee = (struct sock_extended_err *) CMSG_DATA (cm);		    if (ee->ee_origin != SO_EE_ORIGIN_ICMP)			    ee = NULL;		}	    }	    else if (cm->cmsg_level == SOL_IPV6) {		if (cm->cmsg_type == IPV6_HOPLIMIT)			pb->recv_ttl = *((int *) CMSG_DATA (cm));		else if (cm->cmsg_type == IPV6_RECVERR) {		    ee = (struct sock_extended_err *) CMSG_DATA (cm);		    if (ee->ee_origin != SO_EE_ORIGIN_ICMP6)			    ee = NULL;		}	    }	}	if (ee) {	    memcpy (&pb->res, SO_EE_OFFENDER (ee), sizeof(pb->res));	    parse_icmp_res (pb, ee->ee_type, ee->ee_code, ee->ee_info);	}	if (!pb->recv_time)	    pb->recv_time = get_time ();	if (ee &&	    mtudisc &&	    ee->ee_info >= header_len &&	    ee->ee_info < header_len + data_len	) {	    data_len = ee->ee_info - header_len;	    probe_done (pb);	    /*  clear this probe (as actually the previous hop answers here)	      but fill its `err_str' by the info obtained. Ugly, but easy...	    */	    memset (pb, 0, sizeof (*pb));	    snprintf (pb->err_str, sizeof(pb->err_str)-1, "F=%d", ee->ee_info);	    return;	}	if (ee &&	    extension &&	    header_len + n >= (128 + 8) &&	/*  at least... (rfc4884)  */	    header_len <= 128 &&	/*  paranoia   */	    ((af == AF_INET && (ee->ee_type == ICMP_TIME_EXCEEDED ||				ee->ee_type == ICMP_DEST_UNREACH ||				ee->ee_type == ICMP_PARAMETERPROB)) ||	     (af == AF_INET6 && (ee->ee_type == ICMP6_TIME_EXCEEDED ||				 ee->ee_type == ICMP6_DST_UNREACH))	    )	) {	    int step;	    int offs = 128 - header_len;	    if (n > data_len)  step = 0;	/*  guaranteed at 128 ...  */	    else		step = af == AF_INET ? 4 : 8;	    handle_extensions (pb, bufp + offs, n - offs, step);	}	probe_done (pb);}int equal_addr (const sockaddr_any *a, const sockaddr_any *b) {	if (!a->sa.sa_family)		return 0;	if (a->sa.sa_family != b->sa.sa_family)		return 0;	if (a->sa.sa_family == AF_INET6)	    return  !memcmp (&a->sin6.sin6_addr, &b->sin6.sin6_addr,						sizeof (a->sin6.sin6_addr));	else	    return  !memcmp (&a->sin.sin_addr, &b->sin.sin_addr,						sizeof (a->sin.sin_addr));	return 0;	/*  not reached   */}void bind_socket (int sk) {	sockaddr_any *addr, tmp;	if (device) {	    if (setsockopt (sk, SOL_SOCKET, SO_BINDTODEVICE,					device, strlen (device) + 1) < 0	    )  error ("setsockopt SO_BINDTODEVICE");	}	if (!src_addr.sa.sa_family) {	    memset (&tmp, 0, sizeof (tmp));	    tmp.sa.sa_family = af;	    addr = &tmp;	} else	    addr = &src_addr;	if (bind (sk, &addr->sa, sizeof (*addr)) < 0)		error ("bind");	return;}void use_timestamp (int sk) {	int n = 1;	setsockopt (sk, SOL_SOCKET, SO_TIMESTAMP, &n, sizeof (n));	/*  foo on errors...  */}void use_recv_ttl (int sk) {	int n = 1;	if (af == AF_INET)		setsockopt (sk, SOL_IP, IP_RECVTTL, &n, sizeof (n));	else if (af == AF_INET6)		setsockopt (sk, SOL_IPV6, IPV6_RECVHOPLIMIT, &n, sizeof (n));	/*  foo on errors   */}void use_recverr (int sk) {	int val = 1;	if (af == AF_INET) {	    if (setsockopt (sk, SOL_IP, IP_RECVERR, &val, sizeof (val)) < 0)		    error ("setsockopt IP_RECVERR");	}	else if (af == AF_INET6) {	    if (setsockopt (sk, SOL_IPV6, IPV6_RECVERR, &val, sizeof (val)) < 0)		    error ("setsockopt IPV6_RECVERR");	}}void set_ttl (int sk, int ttl) {	if (af == AF_INET) {	    if (setsockopt (sk, SOL_IP, IP_TTL, &ttl, sizeof (ttl)) < 0)		    error ("setsockopt IP_TTL");	}	else if (af == AF_INET6) {	    if (setsockopt (sk, SOL_IPV6, IPV6_UNICAST_HOPS,						&ttl, sizeof (ttl)) < 0	    )  error ("setsockopt IPV6_UNICAST_HOPS");	}}int do_send (int sk, const void *data, size_t len, const sockaddr_any *addr) {	int res;	if (!addr || raw_can_connect ())		res = send (sk, data, len, 0);	else	    res = sendto (sk, data, len, 0, &addr->sa, sizeof (*addr));	if (res < 0) {	    if (errno == ENOBUFS || errno == EAGAIN)		    return res;	    if (errno == EMSGSIZE)		    return 0;	/*  icmp will say more...  */	    error ("send");	/*  not recoverable   */	}	return res;}/*  There is a bug in the kernel before 2.6.25, which prevents icmp errors  to be obtained by MSG_ERRQUEUE for ipv6 connected raw sockets.*/static int can_connect = -1;#define VER(A,B,C,D)	(((((((A) << 8) | (B)) << 8) | (C)) << 8) | (D))int raw_can_connect (void) {	if (can_connect < 0) {	    if (af == AF_INET)		    can_connect = 1;	    else {	/*  AF_INET6   */		struct utsname uts;		int n;		unsigned int a, b, c, d = 0;		if (uname (&uts) < 0)			return 0;		n = sscanf (uts.release, "%u.%u.%u.%u", &a, &b, &c, &d);		can_connect = (n >= 3 && VER (a, b, c, d) >= VER (2, 6, 25, 0));	    }	}	return can_connect;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -