📄 mtrace.c
字号:
else log(LOG_ERR, 0, "while checking for Solaris bug: Sent %d bytes and got back %d!", IGMP_MINLEN + 8, ip->ip_len); break; } }}#endif/* * Construct an IGMP message in the output packet buffer. The caller may * have already placed data in that buffer, of length 'datalen'. Then send * the message from the interface with IP address 'src' to destination 'dst'. */voidsend_igmp(src, dst, type, code, group, datalen) u_int32 src, dst; int type, code; u_int32 group; int datalen;{ struct sockaddr_in sdst; struct ip *ip; struct igmp *igmp; int setloop = 0; static int raset = 0; int sendra = 0; int sendlen; ip = (struct ip *)send_buf; ip->ip_src.s_addr = src; ip->ip_dst.s_addr = dst; ip->ip_len = MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen; sendlen = ip->ip_len;#ifdef SUNOS5 ip->ip_len += ip_addlen;#endif#ifdef RAW_OUTPUT_IS_RAW ip->ip_len = htons(ip->ip_len);#endif igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN); igmp->igmp_type = type; igmp->igmp_code = code; igmp->igmp_group.s_addr = group; igmp->igmp_cksum = 0; igmp->igmp_cksum = inet_cksum((u_short *)igmp, IGMP_MINLEN + datalen); if (IN_MULTICAST(ntohl(dst))) { k_set_if(src); setloop = 1; k_set_loop(TRUE); if (dst != allrtrs_group) sendra = 1; } if (sendopts && sendra && !raset) { setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, router_alert, sizeof(router_alert)); raset = 1; } else if (!sendra && raset) {#ifdef SUNOS5 /* * SunOS5 < 5.6 cannot properly reset the IP_OPTIONS "socket" * option. Instead, set up a string of 4 EOL's. */ setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, eol, sizeof(eol));#else setsockopt(igmp_socket, IPPROTO_IP, IP_OPTIONS, NULL, 0);#endif raset = 0; } bzero(&sdst, sizeof(sdst)); sdst.sin_family = AF_INET;#if (defined(BSD) && (BSD >= 199103)) sdst.sin_len = sizeof(sdst);#endif sdst.sin_addr.s_addr = dst; if (sendto(igmp_socket, send_buf, sendlen, 0, (struct sockaddr *)&sdst, sizeof(sdst)) < 0) { log(LOG_WARNING, errno, "sendto to %s on %s", inet_fmt(dst, s1), inet_fmt(src, s2)); } if (setloop) k_set_loop(FALSE); log(LOG_DEBUG, 0, "SENT %s from %-15s to %s", type == IGMP_MTRACE ? "mtrace request" : "ask_neighbors", src == INADDR_ANY ? "INADDR_ANY" : inet_fmt(src, s1), inet_fmt(dst, s2));}/* * inet_cksum extracted from: * P I N G . C * * Author - * Mike Muuss * U. S. Army Ballistic Research Laboratory * December, 1983 * Modified at Uc Berkeley * * (ping.c) Status - * Public Domain. Distribution Unlimited. * * I N _ C K S U M * * Checksum routine for Internet Protocol family headers (C Version) * */intinet_cksum(addr, len) u_short *addr; u_int len;{ register int nleft = (int)len; register u_short *w = addr; u_short answer = 0; register int sum = 0; /* * Our algorithm is simple, using a 32 bit accumulator (sum), * we add sequential 16 bit words to it, and at the end, fold * back all the carry bits from the top 16 bits into the lower * 16 bits. */ while (nleft > 1) { sum += *w++; nleft -= 2; } /* mop up an odd byte, if necessary */ if (nleft == 1) { *(u_char *) (&answer) = *(u_char *)w ; sum += answer; } /* * add back carry outs from top 16 bits to low 16 bits */ sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* truncate to 16 bits */ return (answer);}voidk_set_rcvbuf(bufsize) int bufsize;{ if (setsockopt(igmp_socket, SOL_SOCKET, SO_RCVBUF, (char *)&bufsize, sizeof(bufsize)) < 0) log(LOG_ERR, errno, "setsockopt SO_RCVBUF %u", bufsize);}voidk_hdr_include(bool) int bool;{#ifdef IP_HDRINCL if (setsockopt(igmp_socket, IPPROTO_IP, IP_HDRINCL, (char *)&bool, sizeof(bool)) < 0) log(LOG_ERR, errno, "setsockopt IP_HDRINCL %u", bool);#endif}voidk_set_ttl(t) int t;{ u_char ttl; ttl = t; if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0) log(LOG_ERR, errno, "setsockopt IP_MULTICAST_TTL %u", ttl);}voidk_set_loop(l) int l;{ u_char loop; loop = l; if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0) log(LOG_ERR, errno, "setsockopt IP_MULTICAST_LOOP %u", loop);}voidk_set_if(ifa) u_int32 ifa;{ struct in_addr adr; adr.s_addr = ifa; if (setsockopt(igmp_socket, IPPROTO_IP, IP_MULTICAST_IF, (char *)&adr, sizeof(adr)) < 0) log(LOG_ERR, errno, "setsockopt IP_MULTICAST_IF %s", inet_fmt(ifa, s1));}voidk_join(grp, ifa) u_int32 grp; u_int32 ifa;{ struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = grp; mreq.imr_interface.s_addr = ifa; if (setsockopt(igmp_socket, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) log(LOG_WARNING, errno, "can't join group %s on interface %s", inet_fmt(grp, s1), inet_fmt(ifa, s2));}voidk_leave(grp, ifa) u_int32 grp; u_int32 ifa;{ struct ip_mreq mreq; mreq.imr_multiaddr.s_addr = grp; mreq.imr_interface.s_addr = ifa; if (setsockopt(igmp_socket, IPPROTO_IP, IP_DROP_MEMBERSHIP, (char *)&mreq, sizeof(mreq)) < 0) log(LOG_WARNING, errno, "can't leave group %s on interface %s", inet_fmt(grp, s1), inet_fmt(ifa, s2));}/* * Convert an IP address in u_long (network) format into a printable string. */char *inet_fmt(addr, s) u_int32 addr; char *s;{ register u_char *a; a = (u_char *)&addr; sprintf(s, "%u.%u.%u.%u", a[0], a[1], a[2], a[3]); return (s);}/* * Convert an IP subnet number in u_long (network) format into a printable * string including the netmask as a number of bits. */char *inet_fmts(addr, mask, s) u_int32 addr, mask; char *s;{ register u_char *a, *m; int bits; if ((addr == 0) && (mask == 0)) { sprintf(s, "default"); return (s); } a = (u_char *)&addr; m = (u_char *)&mask; bits = 33 - ffs(ntohl(mask)); if (m[3] != 0) sprintf(s, "%u.%u.%u.%u/%d", a[0], a[1], a[2], a[3], bits); else if (m[2] != 0) sprintf(s, "%u.%u.%u/%d", a[0], a[1], a[2], bits); else if (m[1] != 0) sprintf(s, "%u.%u/%d", a[0], a[1], bits); else sprintf(s, "%u/%d", a[0], bits); return (s);}char *inet_name(addr) u_int32 addr;{ struct hostent *e; e = gethostbyaddr((char *)&addr, sizeof(addr), AF_INET); return e ? e->h_name : "?";}u_int32 host_addr(name) char *name;{ struct hostent *e = (struct hostent *)0; u_int32 addr; int i, dots = 3; char buf[40]; char *ip = name; char *op = buf; /* * Undo BSD's favor -- take fewer than 4 octets as net/subnet address * if the name is all numeric. */ for (i = sizeof(buf) - 7; i > 0; --i) { if (*ip == '.') --dots; else if (*ip == '\0') break; else if (!isdigit(*ip)) dots = 0; /* Not numeric, don't add zeroes */ *op++ = *ip++; } for (i = 0; i < dots; ++i) { *op++ = '.'; *op++ = '0'; } *op = '\0'; if (dots <= 0) e = gethostbyname(name); if (e && (e->h_length == sizeof(addr))) { memcpy((char *)&addr, e->h_addr_list[0], e->h_length); if (e->h_addr_list[1]) fprintf(stderr, "Warning: %s has multiple addresses, using %s\n", name, inet_fmt(addr, s1)); } else { addr = inet_addr(buf); if (addr == -1 || (IN_MULTICAST(addr) && dots)) { addr = 0; printf("Could not parse %s as host name or address\n", name); } } return addr;}char *proto_type(type) u_int type;{ static char buf[80]; switch (type) { case PROTO_DVMRP: return ("DVMRP"); case PROTO_MOSPF: return ("MOSPF"); case PROTO_PIM: return ("PIM"); case PROTO_CBT: return ("CBT"); case PROTO_PIM_SPECIAL: return ("PIM/Special"); case PROTO_PIM_STATIC: return ("PIM/Static"); case PROTO_DVMRP_STATIC: return ("DVMRP/Static"); case PROTO_PIM_BGP4PLUS: return ("PIM/BGP4+"); case PROTO_CBT_SPECIAL: return ("CBT/Special"); case PROTO_CBT_STATIC: return ("CBT/Static"); case PROTO_PIM_ASSERT: return ("PIM/Assert"); case 0: return ("None"); default: (void) sprintf(buf, "Unknown protocol code %d", type); return (buf); }}char *flag_type(type) u_int type;{ static char buf[80]; switch (type) { case TR_NO_ERR: return (""); case TR_WRONG_IF: return ("Wrong interface"); case TR_PRUNED: return ("Prune sent upstream"); case TR_OPRUNED: return ("Output pruned"); case TR_SCOPED: return ("Hit scope boundary"); case TR_NO_RTE: return ("No route"); case TR_NO_FWD: return ("Not forwarding"); case TR_HIT_RP: return ("Reached RP/Core"); case TR_RPF_IF: return ("RPF Interface"); case TR_NO_MULTI: return ("Multicast disabled"); case TR_OLD_ROUTER: return ("Next router no mtrace"); case TR_NO_SPACE: return ("No space in packet"); case TR_ADMIN_PROHIB: return ("Admin. Prohibited"); default: (void) sprintf(buf, "Unknown error code %d", type); return (buf); }} /* * If destination is on a local net, get the netmask, else set the * netmask to all ones. There are two side effects: if the local * address was not explicitly set, and if the destination is on a * local net, use that one; in either case, verify that the local * address is valid. */u_int32get_netmask(s, dst) int s; u_int32 *dst;{ unsigned int n; struct ifconf ifc; struct ifreq *ifrp, *ifend; u_int32 if_addr, if_mask; u_int32 retval = 0xFFFFFFFF; int found = FALSE; int num_ifreq = 32; ifc.ifc_len = num_ifreq * sizeof(struct ifreq); ifc.ifc_buf = malloc(ifc.ifc_len); while (ifc.ifc_buf) { if (ioctl(s, SIOCGIFCONF, (char *)&ifc) < 0) { perror("ioctl SIOCGIFCONF"); return retval; } /* * If the buffer was large enough to hold all the addresses * then break out, otherwise increase the buffer size and * try again. * * The only way to know that we definitely had enough space * is to know that there was enough space for at least one * more struct ifreq. ??? */ if ((num_ifreq * sizeof(struct ifreq)) >= ifc.ifc_len + sizeof(struct ifreq)) break; num_ifreq *= 2; ifc.ifc_len = num_ifreq * sizeof(struct ifreq); ifc.ifc_buf = realloc(ifc.ifc_buf, ifc.ifc_len); } if (ifc.ifc_buf == NULL) { fprintf(stderr, "getting interface list: ran out of memory"); exit(1); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -