📄 traceroute.c
字号:
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 + -