ssmping-0.9.1/0000755000223200001440000000000011002120443012354 5ustar venaasusersssmping-0.9.1/ssmpngcl.c0000644000223200001440000005762610756305436014414 0ustar venaasusers/* * Copyright (C) 2005, 2006 Stig Venaas * $Id:$ * * Contributions: * Solaris support by Alexander Gall * Initial Windows support by Nick Lamb * llsqrt() taken from Linux's iputils package * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" #ifdef WIN32 #include #include /* further definitions missing from my mswsock.h */ #ifndef WSAID_WSARECVMSG /* http://cvs.winehq.org/cvsweb/wine/include/mswsock.h */ #define WSAID_WSARECVMSG {0xf689d7c8,0x6f1f,0x436b,{0x8a,0x53,0xe5,0x4f,0xe3,0x51,0xc3,0x22}} #endif #ifndef CMSG_FIRSTHDR #define CMSG_FIRSTHDR(pwsamsg) (pwsamsg)->Control.len >= sizeof(WSACMSGHDR) ? (WSACMSGHDR *)((pwsamsg)->Control.buf) : NULL #endif #ifndef CMSG_NXTHDR #define CMSG_NXTHDR(pwsamsg, cmsg) my_cmsg_nxthdr(pwsamsg, cmsg) WSACMSGHDR *my_cmsg_nxthdr(WSAMSG *mhdr, WSACMSGHDR *cmsg) { WSACMSGHDR *cmsgh = (WSACMSGHDR *)(((char *)cmsg) + cmsg->cmsg_len); /* should also do alignment above */ return (char *)(cmsgh + 1) <= (char *)mhdr->Control.buf + mhdr->Control.len ? cmsgh : NULL; } #endif #ifndef MSG_MCAST #define MSG_MCAST 2048 #endif #ifndef IPV6_HOPLIMIT #define IPV6_HOPLIMIT 21 #endif #ifndef CMSG_DATA #define MY_CMSG_LEN(len) (len)+sizeof(WSACMSGHDR) #define CMSG_DATA(cmsg) ((char *)(cmsg)+sizeof(WSACMSGHDR)) #endif #ifndef _CMSG_DATA_ALIGN #define _CMSG_DATA_ALIGN(len) (((len) + sizeof (size_t) - 1) & (size_t) ~(sizeof (size_t) - 1)) #endif #endif #ifndef MY_CMSG_LEN #define MY_CMSG_LEN CMSG_LEN #endif /* llsqrt() taken from Linux's iputils package */ static long llsqrt(unsigned long long a) { long long prev = ~((unsigned long long) 1 << 63); long long x = a; if (x > 0) { while (x < prev) { prev = x; x = (x + (a / x)) / 2; } } return (long) x; } void gettime(struct timeval *tv) { #ifdef WIN32 long long hns; FILETIME ft; GetSystemTimeAsFileTime(&ft); hns = (4294967296LL * ft.dwHighDateTime + ft.dwLowDateTime) / 10 - 11644473600000000LL ; /* fix up UNIX 1970 vs Win32 1601 */ tv->tv_sec = (hns / 1000000); tv->tv_usec = (hns % 1000000); #else gettimeofday(tv, NULL); #endif } void setport(struct sockaddr *sa, int port) { switch (sa->sa_family) { case AF_INET: { struct sockaddr_in *sin = (struct sockaddr_in *)sa; sin->sin_port = htons(port); return; } case AF_INET6: { struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; sin6->sin6_port = htons(port); return; } } } /* returns t2 - t1 if t2 > t1, else 0 */ void timediff(struct timeval *diff, struct timeval *t1, struct timeval *t2) { if (t2->tv_sec >= t1->tv_sec) { diff->tv_sec = t2->tv_sec - t1->tv_sec; if (t2->tv_usec >= t1->tv_usec) { diff->tv_usec = t2->tv_usec - t1->tv_usec; return; } if (diff->tv_sec) { diff->tv_sec--; diff->tv_usec = 1000000 - t1->tv_usec + t2->tv_usec; return; } } diff->tv_sec = 0; diff->tv_usec = 0; return; } /* returns -1, 0, 1 if t1 < t2, t1 == t2, t1 > t2 resp */ int timecmp(struct timeval *t1, struct timeval *t2) { if (t1->tv_sec < t2->tv_sec) return -1; if (t1->tv_sec > t2->tv_sec) return 1; if (t1->tv_usec < t2->tv_usec) return -1; if (t1->tv_usec > t2->tv_usec) return 1; return 0; } int addr_equal(struct sockaddr *a, struct sockaddr *b) { switch (a->sa_family) { case AF_INET: return !memcmp(&((struct sockaddr_in*)a)->sin_addr, &((struct sockaddr_in*)b)->sin_addr, sizeof(struct in_addr)); case AF_INET6: return IN6_ARE_ADDR_EQUAL(&((struct sockaddr_in6*)a)->sin6_addr, &((struct sockaddr_in6*)b)->sin6_addr); default: /* Must not reach */ return 1; } } int dupcheck(char s, unsigned int t) { static int first = 1; static unsigned int recent[2][100]; int i = s % 2; int j = t % 100; if (first) { first = 0; memset(recent, 0, sizeof(recent)); recent[0][0] = 1; recent[1][0] = 1; } if (recent[i][j] == t) return 1; recent[i][j] = t; return 0; } void prep_sock(int family, int s) { int on = 1; if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) == -1) errx("setsockopt SO_REUSEADDR"); #ifdef SO_TIMESTAMP if (setsockopt(s, SOL_SOCKET, SO_TIMESTAMP, (char *)&on, sizeof(on)) == -1) errx("setsockopt SO_TIMESTAMP"); #endif switch (family) { case AF_INET6: #ifdef IPV6_RECVHOPLIMIT if (setsockopt(s, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) errx("setsockopt IPV6_RECVHOPLIMIT"); #else if (setsockopt(s, IPPROTO_IPV6, IPV6_HOPLIMIT, (char *)&on, sizeof(on)) == -1) errx("setsockopt IPV6_HOPLIMIT"); #endif break; case AF_INET: #ifdef IP_RECVTTL if (setsockopt(s, IPPROTO_IP, IP_RECVTTL, &on, sizeof(on)) == -1) errx("setsockopt IP_RECVTTL"); #else if (setsockopt(s, IPPROTO_IP, IP_TTL, (char *)&on, sizeof(on)) == -1) errx("setsockopt IP_TTL"); #endif break; } } void findsrc(struct sockaddr *src, struct sockaddr *dst) { int s; socklen_t len; len = dst->sa_family == AF_INET6 ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in); s = socket(dst->sa_family, SOCK_DGRAM, 0); if (s < 0) errx("socket"); /* connect to get sockname */ if (connect(s, dst, len) < 0) errx("connect"); if (getsockname(s, src, &len) == -1) errx("getsockname"); close(s); } /* mc is a flag saying if multicast or unicast, only used on WIN32 */ int recvfromhopstime(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen, int32_t *hops, struct timeval *tstamp, char *mc) { #ifdef WIN32 GUID WSARecvMsg_GUID = WSAID_WSARECVMSG; long ioctlcount; static int (*WSARecvMsg)() = NULL; WSAMSG msgh; WSABUF iovec; WSACMSGHDR *cmsgh; #else struct msghdr msgh; struct iovec iovec; struct cmsghdr *cmsgh; #endif char control[1024]; int cnt; #ifdef WIN32 if (!WSARecvMsg) { if (WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &WSARecvMsg_GUID, sizeof(WSARecvMsg_GUID), &WSARecvMsg, sizeof(WSARecvMsg), &ioctlcount, NULL, NULL)) { fprintf(stderr, "WSAIoctl failed with code %d\n", WSAGetLastError()); return -1; } } #endif if (hops) *hops = -1; if (tstamp) memset(tstamp, 0, sizeof(struct timeval)); #ifdef WIN32 memset(&msgh, 0, sizeof(msgh)); msgh.lpBuffers = &iovec; msgh.dwBufferCount = 1; msgh.Control.buf = control; msgh.Control.len = sizeof(control); memset(control, 0, sizeof(control)); msgh.name = from; msgh.namelen = *fromlen; msgh.dwFlags = 0; memset(&iovec, 0, sizeof(iovec)); iovec.buf = buf; iovec.len = len; if (WSARecvMsg(s, &msgh, &cnt, NULL, NULL)) { fprintf(stderr, "WSARecvMsg failed with code %d\n", WSAGetLastError()); return -1; } if (mc) *mc = (msgh.dwFlags & MSG_MCAST) == MSG_MCAST; #else memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_iov = &iovec; msgh.msg_iovlen = 1; msgh.msg_control = control; msgh.msg_controllen = sizeof(control); msgh.msg_name = from; msgh.msg_namelen = *fromlen; memset(&iovec, 0, sizeof(struct iovec)); iovec.iov_base = (caddr_t)buf; iovec.iov_len = len; cnt = recvmsg(s, &msgh, 0); #endif if (cnt < 1 || (!hops && !tstamp)) return cnt; #if 0 printf("flags=%d\n", msgh.dwFlags); { int i; for (i = 0; i < 16; i++) printf("%hhd\n", control[i]); } printf("control length = %d\n", msgh.Control.len); #endif for (cmsgh = CMSG_FIRSTHDR(&msgh); cmsgh; cmsgh = CMSG_NXTHDR(&msgh, cmsgh)) switch (cmsgh->cmsg_level) { #ifdef SCM_TIMESTAMP case SOL_SOCKET: if (cmsgh->cmsg_type == SCM_TIMESTAMP && cmsgh->cmsg_len >= MY_CMSG_LEN(sizeof(struct timeval))) *tstamp = *(struct timeval *)CMSG_DATA(cmsgh); break; #endif case IPPROTO_IP: if (cmsgh->cmsg_type == IP_TTL && cmsgh->cmsg_len >= MY_CMSG_LEN(sizeof(int32_t))) *hops = *(int *)CMSG_DATA(cmsgh); #ifdef IP_RECVTTL /* Only found Solaris 9 to use IP_RECVTTL so far */ if (cmsgh->cmsg_type == IP_RECVTTL && cmsgh->cmsg_len >= 13) *hops = *(int8_t *)CMSG_DATA(cmsgh); #endif break; case IPPROTO_IPV6: if (cmsgh->cmsg_type == IPV6_HOPLIMIT && cmsgh->cmsg_len >= MY_CMSG_LEN(sizeof(int))) *hops = *(int *)CMSG_DATA(cmsgh); break; } return cnt; } size_t initsendbuf(char *buf, size_t buflen, pid_t pid, int ver, uint16_t size, struct sockaddr_storage *group, void **seq, void **timestamp) { char *p = buf; uint32_t int32[2]; if (buflen < 1) errx("Send buffer too small"); *p++ = SSMPING_REQUEST; if (p + tlvspace(4) > buf + buflen) errx("Send buffer too small"); int32[0] = pid; int32[0] = htonl(int32[0]); p = tlvadd(p, SSMPING_PID, 4, int32); p += 4; int32[0] = 0; int32[1] = 0; if (p + tlvspace(4) > buf + buflen) errx("Send buffer too small"); p = tlvadd(p, SSMPING_SEQ, 4, int32); *seq = p; p += 4; if (p + tlvspace(8) > buf + buflen) errx("Send buffer too small"); p = tlvadd(p, SSMPING_TIMESTAMP, 8, int32); *timestamp = p; p += 8; if (ver) { if (p + tlvspace(0) > buf + buflen) errx("Send buffer too small"); p = tlvadd(p, SSMPING_RQVER, 0, NULL); } if (size) { uint16_t tsize = htons(size); if (p + tlvspace(2) > buf + buflen) errx("Send buffer too small"); p = tlvadd(p, SSMPING_REPLYSIZE, 2, &tsize); p += 2; } switch (((struct sockaddr *)group)->sa_family) { case AF_INET: if (p + tlvspace(5) > buf + buflen) errx("Send buffer too small"); /* ugly hack, starting 1 byte before address to have room for family */ p = tlvadd(p, SSMPING_GROUP, 5, ((char *)&(((struct sockaddr_in *)group)->sin_addr)) - 1); *p = 1; /* IANA has assigned 1 for IPv4 */ p += 5; break; case AF_INET6: if (p + tlvspace(17) > buf + buflen) errx("Send buffer too small"); /* ugly hack, starting 1 byte before address to have room for family */ p = tlvadd(p, SSMPING_GROUP, 17, ((char *)&(((struct sockaddr_in6 *)group)->sin6_addr)) - 1); *p = 2; /* IANA has assigned 2 for IPv6 */ p += 17; break; } return p - buf; } int parsepacket(char *buf, size_t len, char **verstring, struct ssmpingdata *data) { uint16_t t, l, tmp; char *v, *p = buf; uint32_t val; int pid = 0, seq = 0, timestamp = 0; while (p - buf + 4 <= len) { memcpy(&tmp, p, 2); t = ntohs(tmp); p += 2; memcpy(&tmp, p, 2); l = ntohs(tmp); p += 2; if (l) { if (p - buf + l > len) return -1; v = p; p += l; } switch (t) { case SSMPING_PID: if (l != 4) return -1; memcpy(&val, v, 4); data->pid = ntohl(val); pid = 1; break; case SSMPING_SEQ: if (l != 4) return -1; memcpy(&val, v, 4); data->seq = ntohl(val); seq = 1; break; case SSMPING_TIMESTAMP: if (l != 8) return -1; memcpy(&val, v, 4); data->timestamp.tv_sec = ntohl(val); memcpy(&val, v + 4, 4); data->timestamp.tv_usec = ntohl(val); timestamp = 1; break; case SSMPING_VER: if (!l) return -1; if (!*verstring) { *verstring = malloc(l); if (*verstring) { memcpy(*verstring, v, l); (*verstring)[l] = '\0'; } } break; } } if (p - buf != len) return -1; return 0; } int ismc(struct sockaddr *sa) { switch (sa->sa_family) { case AF_INET: return IN_MULTICAST(ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr)); case AF_INET6: return IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6 *)sa)->sin6_addr); } return 0; } #ifdef WIN32 #ifndef DNS_TYPE_SRV #define DNS_TYPE_SRV 33 #endif char *getsrv(const char *name) { DNS_RECORD *dnsrecords, *dnsrecord; void *dnsrsv; char *srvname; srvname = malloc(strlen(name) + strlen("_ldap._tcp.") + 1); sprintf(srvname, "_ldap._tcp.%s", name); if (DnsQuery_A(srvname, DNS_TYPE_SRV, DNS_QUERY_STANDARD, NULL, &dnsrecords, &dnsrsv)) return NULL; for (dnsrecord = dnsrecords; dnsrecord; dnsrecord = dnsrecord->pNext) { #if 0 printf("dnsname = %s\n", dnsrecord->pName); printf("dnstype = %d\n", dnsrecord->wType); #endif if (dnsrecord->wType == DNS_TYPE_SRV) { free(srvname); return dnsrecord->Data.Srv.pNameTarget; } } free(srvname); DnsRecordListFree(dnsrecords, DnsFreeRecordList); return NULL; } #endif /* return 0 if ok, -1 on error. creates sockets s1, s2 if not NULL * mcaddr must be mc and ucaddr uc, unless both specified, in which * case one must be uc and the other mc */ int names2addrsocks(int *s1, int *s2, const char *ucaddr, const char *mcaddr, const char *srv, int *family, struct sockaddr_storage *ucsa, struct sockaddr_storage *mcsa) { struct addrinfo hints, *res1, *res2; const char *addr; int e; addr = mcaddr ? mcaddr : ucaddr; if (!addr) return -1; if (s1) *s1 = -1; if (s2) *s2 = -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = *family; hints.ai_socktype = SOCK_DGRAM; #ifdef WIN32 printf("SRV target %s\n", getsrv(addr)); #endif if ((e = getaddrinfo(addr, srv, &hints, &res1))) { #ifdef WIN32 err("getaddrinfo failed with error code %d", e); #else err("getaddrinfo failed: %s", gai_strerror(e)); #endif return -1; } for (; res1; res1 = res1->ai_next) { if (s1) { *s1 = socket(res1->ai_family, res1->ai_socktype, res1->ai_protocol); if (*s1 < 0) { err("socket"); continue; } } if (s2) { *s2 = socket(res1->ai_family, res1->ai_socktype, res1->ai_protocol); if (*s2 < 0) { if (s1) { close(*s1); *s1 = -1; } err("socket"); continue; } } *family = res1->ai_family; if (!ucaddr || !mcaddr) { if (ismc(res1->ai_addr)) { if (mcaddr) { memcpy(mcsa, res1->ai_addr, res1->ai_addrlen); return 0; } err("Argument must be a unicast address"); return -1; } if (ucaddr) { memcpy(ucsa, res1->ai_addr, res1->ai_addrlen); return 0; } err("Argument must be a multicast address"); return -1; } hints.ai_family = *family; if ((e = getaddrinfo(ucaddr, srv, &hints, &res2))) { #ifdef WIN32 err("getaddrinfo failed with error code %d", e); #else err("getaddrinfo failed: %s", gai_strerror(e)); #endif if (s1) { close(*s1); *s1 = -1; } if (s2) { close(*s2); *s2 = -1; } continue; } if (ismc(res1->ai_addr)) { if (ismc(res2->ai_addr)) { err("Both addresses cannot be multicast addresses"); return -1; } memcpy(mcsa, res1->ai_addr, res1->ai_addrlen); memcpy(ucsa, res2->ai_addr, res2->ai_addrlen); return 0; } if (ismc(res2->ai_addr)) { memcpy(ucsa, res1->ai_addr, res1->ai_addrlen); memcpy(mcsa, res2->ai_addr, res2->ai_addrlen); return 0; } err("Both addresses cannot be unicast addresses"); return -1; } return -1; } void parseargs(int argc, char **argv, int mode, int *family, int *ver, uint16_t *size, uint32_t *intface, int *count, char **addr1, char **addr2, uint16_t *runtime, uint16_t *rate, char **srv) { int c; *family = AF_UNSPEC; *intface = 0; *count = 0; *addr2 = NULL; *ver = 0; if (size) *size = 0; if (runtime) *runtime = 0; if (rate) *rate = 0; while ((c = getopt(argc, argv, #ifdef WIN32 mode == FIRSTMODE ? "46vrc:t:" : "46vc:s:" #else mode == FIRSTMODE ? "46vrI:c:t:" : "46vI:c:s:" #endif )) != -1) { switch (c) { case '4': *family = AF_INET; break; case '6': *family = AF_INET6; break; case 'v': *ver = 1; break; case 'r': if (rate) *rate = 1; break; #ifndef WIN32 case 'I': *intface = if_nametoindex(optarg); if (*intface) break; fprintf(stderr, "Unknown interface %s\n", optarg); exit(1); #endif case 'c': *count = atoi(optarg); if (*count > 0) break; fprintf(stderr, "Count must be positive\n"); goto usage; case 's': *size = atoi(optarg); if (*size > 0) break; fprintf(stderr, "Invalid size\n"); goto usage; case 't': *runtime = atoi(optarg); if (*runtime > 0) break; fprintf(stderr, "Invalid time to run\n"); goto usage; default: goto usage; } } switch (mode) { case FIRSTMODE: /* require two-three more arguments */ switch (argc - optind) { case 2: *addr1 = argv[optind++]; *srv = argv[optind]; return; case 3: *addr1 = argv[optind++]; *addr2 = argv[optind++]; *srv = argv[optind]; return; default: goto usage; } case ASMMODE: /* require exactly two arguments after the options */ if (argc - optind != 2) goto usage; *addr2 = argv[optind++]; *addr1 = argv[optind]; return; case SSMMODE: /* require exactly one more argument */ if (argc - optind != 1) goto usage; *addr1 = argv[optind]; return; } usage: fprintf(stderr, "%s version %s\n\n", argv[0], SSMPING_VERSIONSTRING); switch (mode) { case FIRSTMODE: fprintf(stderr, #ifdef WIN32 "Usage:\n%s [ -46vr ] [ -c count ] [ -t time ] [source] group port\nor\n%s [ -46vr ] [ -c count ] [ -t time ] group [source] port\n" #else "Usage:\n%s [ -46vr ] [ -I interface ] [ -c count ] [ -t time ] [source] group port\nor\n%s [ -46vr ] [ -I interface ] [ -c count ] [ -t time ] group [source] port\n" #endif , argv[0], argv[0]); break; case ASMMODE: fprintf(stderr, #ifdef WIN32 "Usage:\n%s [ -46v ] [ -c count ] [ -s size ] group destination\nor\n%s [ -46v ] [ -c count ] [ -s size ] destination group\n" #else "Usage:\n%s [ -46v ] [ -I interface ] [ -c count ] [ -s size ] group destination\nor\n%s [ -46v ] [ -I interface ] [ -c count ] [ -s size ] destination group\n" #endif , argv[0], argv[0]); break; case SSMMODE: fprintf(stderr, #ifdef WIN32 "Usage:\n%s [ -46v ] [ -c count ] [ -s size ] destination\n" #else "Usage:\n%s [ -46v ] [ -I interface ] [ -c count ] [ -s size ] destination\n" #endif , argv[0]); break; } exit(1); } /* finish needs to be visible for interrupt() */ int finish = 0; void interrupt(int signo) { finish = 1; } int doit(int ver, int size, int count, int us, int ms, struct sockaddr_storage *ucaddr, struct sockaddr_storage *grpaddr, char *source) { int s, cnt, max, ndesc, gotver = 0; int32_t hops; unsigned int uccount = 0, mccount = 0, mcminseq; long rtt, ucmin, ucmax, mcmin, mcmax, mdev; long long ucsum, ucsqsum, mcsum, mcsqsum, mean; fd_set readfds; pid_t pid; struct ssmpingdata recvdata; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); size_t sendbuflen, recvbuflen, sendlen; struct timeval now, jointime, tstamp, diff, timeout, nextping; char mc, sendbuf[1024], recvbuf[1024], *sendtimestamp, *verstring = NULL; void *sendseq; uint32_t u32t, seq = 0; int32_t dist; #ifndef WIN32 struct sigaction sa_int; #endif gettime(&jointime); sendbuflen = sizeof(sendbuf); recvbuflen = sizeof(recvbuf); pid = getpid(); sendlen = initsendbuf(sendbuf, sendbuflen, pid, ver, size, grpaddr, &sendseq, (void **)&sendtimestamp); max = us > ms ? us : ms; #ifndef WIN32 sa_int.sa_handler = interrupt; sigemptyset(&sa_int.sa_mask); sa_int.sa_flags = 0; sigaction(SIGINT, &sa_int, NULL); #else signal(SIGBREAK, interrupt); signal(SIGINT, interrupt); #endif /* the next ping (the first one), should be immediately */ gettime(&nextping); for(;;) { FD_ZERO(&readfds); FD_SET(us, &readfds); FD_SET(ms, &readfds); /* set timeout to now - nextping or 0 if past nextping time */ gettime(&now); timediff(&timeout, &now, &nextping); ndesc = select(max + 1, &readfds, (fd_set *)0, (fd_set *)0, &timeout); gettime(&now); if (finish) break; if (timecmp(&nextping, &now) <= 0) { if (count && seq >= count) break; nextping.tv_sec++; seq++; u32t = htonl(seq); memcpy(sendseq, &u32t, 4); u32t = htonl(now.tv_sec); memcpy(sendtimestamp, &u32t, 4); u32t = htonl(now.tv_usec); memcpy(sendtimestamp + 4, &u32t, 4); if (send(us, (void *)&sendbuf, sendlen, 0) < 0) err("send"); } if (ndesc < 1) continue; s = FD_ISSET(us, &readfds) ? us : ms; cnt = recvfromhopstime(s, (void *)&recvbuf, recvbuflen, 0, (struct sockaddr *)&from, &fromlen, &hops, &tstamp, &mc); if (cnt == -1) { err("recv failed"); continue; } if (cnt < sendlen) { printf("packet too small\n"); continue; } fromlen = from.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); if (!addr_equal((struct sockaddr *)&from, (struct sockaddr *)ucaddr)) { printf("ignoring packet from wrong host (%s)\n", addr2string((struct sockaddr *) &from, fromlen)); continue; } if (*recvbuf != SSMPING_REPLY) { printf("received non-reply packet\n"); continue; } parsepacket(recvbuf + 1, cnt - 1, &verstring, &recvdata); #ifndef WIN32 mc = s == ms; #endif if (recvdata.pid != pid) { printf("received someone else's %sicast reply\n", mc ? "mult" : "un"); continue; } timediff(&diff, &recvdata.timestamp, tstamp.tv_sec ? &tstamp : &now); if (verstring && !gotver) { gotver = 1; printf("Server version: %s\n", verstring); } if (size && cnt != size) printf("Warning, requested packet size %d, got %d\n", size, cnt); if (hops < 0) dist = -1; else if (hops > 64) /* assuming Windows using ttl 128 */ dist = 128 - hops; else dist = 64 - hops; printf("%sicast from %s, seq=%d dist=%d time=%ld.%03ld ms", mc ? "mult" : " un", addr2string((struct sockaddr *) &from, fromlen), recvdata.seq, dist, diff.tv_sec * 1000 + diff.tv_usec / 1000, diff.tv_usec % 1000); rtt = (long)diff.tv_sec * 1000000 + (long)diff.tv_usec; if (dupcheck(mc, recvdata.seq)) { printf(" (DUP!)\n"); continue; } printf("\n"); if (s == us) { if (uccount == 0) { ucsum = ucmin = ucmax = rtt; ucsqsum = (long long) rtt * rtt; } else { if (rtt < ucmin) ucmin = rtt; if (rtt > ucmax) ucmax = rtt; ucsum += rtt; ucsqsum += (long long) rtt * rtt; } uccount++; } else { if (mccount == 0) { mcminseq = recvdata.seq; mcsum = mcmin = mcmax = rtt; mcsqsum = (long long) rtt * rtt; } else { if (recvdata.seq < mcminseq) mcminseq = recvdata.seq; if (rtt < mcmin) mcmin = rtt; if (rtt > mcmax) mcmax = rtt; mcsum += rtt; mcsqsum += (long long) rtt * rtt; } mccount++; } } timediff(&diff, &jointime, &now); printf("\n"); printf("--- %s statistics ---\n", source); printf("%d packets transmitted, time %ld ms\n", seq, diff.tv_sec * 1000 + diff.tv_usec / 1000); printf("unicast:\n"); printf(" %d packets received, %d%% packet loss\n", uccount, 100 * (seq - uccount) / seq); if (uccount) { mean = ucsum / uccount; mdev = llsqrt(ucsqsum / uccount - mean * mean); printf(" rtt min/avg/max/std-dev = %ld.%03ld/%ld.%03ld/%ld.%03ld/%ld.%03ld ms\n", ucmin / 1000, ucmin % 1000, (unsigned long) mean / 1000, (long) mean % 1000, ucmax / 1000, ucmax % 1000, mdev / 1000, mdev % 1000); } printf("multicast:\n"); if (!mccount) { printf(" 0 packets received, 100%% packet loss\n"); return 1; } printf(" %d packets received, %d%% packet loss since first mc packet (seq %d) recvd\n", mccount, 100 * (seq - mcminseq + 1 - mccount) / (seq - mcminseq + 1), mcminseq /*diff.tv_sec * 1000 + diff.tv_usec / 1000*/ ); mean = mcsum / mccount; mdev = llsqrt(mcsqsum / mccount - mean * mean); printf(" rtt min/avg/max/std-dev = %ld.%03ld/%ld.%03ld/%ld.%03ld/%ld.%03ld ms\n", mcmin / 1000, mcmin % 1000, (unsigned long) mean / 1000, (long) mean % 1000, mcmax / 1000, mcmax % 1000, mdev / 1000, mdev % 1000); return 0; } ssmping-0.9.1/ssmpingd.c0000644000223200001440000002144410756305436014377 0ustar venaasusers/* * Copyright (C) 2005, 2006 Stig Venaas * $Id:$ * * Contributions: * Solaris support by Alexander Gall * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" #ifndef WIN32 void zerosrcinterface(struct msghdr *msgh) { struct cmsghdr *cmsgh; switch (((struct sockaddr *)(msgh->msg_name))->sa_family) { case AF_INET: { #ifdef IP_PKTINFO struct in_pktinfo *pktinfo; for (cmsgh = CMSG_FIRSTHDR(msgh); cmsgh; cmsgh = CMSG_NXTHDR(msgh, cmsgh)) if ((cmsgh->cmsg_level == IPPROTO_IP) && (cmsgh->cmsg_type == IP_PKTINFO)) { pktinfo = (struct in_pktinfo *)CMSG_DATA(cmsgh); pktinfo->ipi_ifindex = 0; break; } #endif /* if not defined we only got source address (I think) */ return; } case AF_INET6: { struct in6_pktinfo *pktinfo; for (cmsgh = CMSG_FIRSTHDR(msgh); cmsgh; cmsgh = CMSG_NXTHDR(msgh, cmsgh)) if ((cmsgh->cmsg_level == IPPROTO_IPV6) && (cmsgh->cmsg_type == IPV6_PKTINFO)) { pktinfo = (struct in6_pktinfo *)CMSG_DATA(cmsgh); pktinfo->ipi6_ifindex = 0; break; } return; } } } #endif int parsequery(char *buf, int len, int *rqver, uint16_t *rqsize, struct sockaddr *group) { uint16_t t, l, tmp; char *v, *p = buf; *rqver = 0; *rqsize = 0; group->sa_family = AF_UNSPEC; while (p - buf + 4 <= len) { memcpy(&tmp, p, 2); t = ntohs(tmp); p += 2; memcpy(&tmp, p, 2); l = ntohs(tmp); p += 2; if (l) { if (p - buf + l > len) return -1; v = p; p += l; } switch (t) { case SSMPING_RQVER: *rqver = 1; break; case SSMPING_REPLYSIZE: if (l != 2) return -1; memcpy(rqsize, v, 2); *rqsize = ntohs(*rqsize); break; case SSMPING_GROUP: if (l < 1) return -1; if (*v == 1) { /* IPv4 */ if (l != 5) return -1; memcpy(&((struct sockaddr_in *)group)->sin_addr, v + 1, 4); group->sa_family = AF_INET; return 0; } if (*v == 2) { /* IPv6 */ if (l != 17) return -1; memcpy(&((struct sockaddr_in6 *)group)->sin6_addr, v + 1, 16); group->sa_family = AF_INET6; return 0; } return -1; } } return -1; } int addrok(struct sockaddr *addr) { switch(addr->sa_family) { case AF_INET: { struct sockaddr_in *a = (struct sockaddr_in *)addr; return *(((uint8_t *)&a->sin_addr) + 3) == 234; } case AF_INET6: { const char groupid[4] = { 0x43, 0x21, 0x12, 0x34 }; struct sockaddr_in6 *a = (struct sockaddr_in6 *)addr; return !memcmp(((char *)&a->sin6_addr) + 12, groupid, 4); } } return 0; } void respond(int s) { static char inbuf[65535], outbuf[65535]; char *p; struct sockaddr *sa, *gsa; struct sockaddr_storage addr, gaddr; socklen_t addrlen = sizeof(addr); int incnt, outcnt, rqver; size_t outbuflen; uint16_t rqsize; #ifndef WIN32 struct msghdr msgh; struct iovec iovec; char control[10240]; #endif sa = (struct sockaddr *)&addr; gsa = (struct sockaddr *)&gaddr; #ifdef WIN32 incnt = recvfrom(s, inbuf, sizeof(inbuf), 0, sa, &addrlen); #else memset(&msgh, 0, sizeof(struct msghdr)); msgh.msg_iov = &iovec; msgh.msg_iovlen = 1; msgh.msg_control = control; msgh.msg_controllen = sizeof(control); msgh.msg_name = (void *)sa; msgh.msg_namelen = addrlen; memset(&iovec, 0, sizeof(struct iovec)); iovec.iov_base = (caddr_t)inbuf; iovec.iov_len = sizeof(inbuf); incnt = recvmsg(s, &msgh, 0); addrlen = msgh.msg_namelen; #endif if (incnt <= 0) return; if (*inbuf != SSMPING_REQUEST) /* not a request, possibly our own reply */ return; printf("received request from %s\n", addr2string(sa, addrlen)); gaddr = addr; /* would be sufficient to copy port */ parsequery(inbuf + 1, incnt - 1, &rqver, &rqsize, gsa); *outbuf = SSMPING_REPLY; memcpy(outbuf + 1, inbuf + 1, incnt - 1); outcnt = incnt; outbuflen = sizeof(outbuf); p = outbuf + outcnt; if (rqver && (p + tlvspace(strlen(SSMPING_SERVERVERSIONSTRING)) < outbuf + outbuflen)) { p = tlvadd(p, SSMPING_VER, strlen(SSMPING_SERVERVERSIONSTRING), SSMPING_SERVERVERSIONSTRING); p += strlen(SSMPING_SERVERVERSIONSTRING); } outcnt = p - outbuf; if (rqsize && (rqsize <= outbuflen) && (outcnt + tlvspace(0) <= rqsize)) { p = tlvaddzero(p, SSMPING_PAD, rqsize - outcnt - tlvspace(0)); outcnt = rqsize; } #ifdef WIN32 /* send unicast */ if (sendto(s, outbuf, outcnt, 0, sa, addrlen) < 0) err("sendto"); #else memset(&iovec, 0, sizeof(struct iovec)); iovec.iov_base = (caddr_t)outbuf; iovec.iov_len = outcnt; /* received ancillary data with destination address and interface */ /* we use that now to specify source address */ /* setting interface to 0, don't want to specify that */ zerosrcinterface(&msgh); /* send unicast */ if (sendmsg(s, &msgh, 0) < 0) err("sendto"); #endif if (gsa->sa_family == AF_UNSPEC) { gsa->sa_family = sa->sa_family; setaddr(&gaddr, NULL, "ff3e::4321:1234", "232.43.211.234"); } else if (!addrok(gsa)) { printf("received request with invalid group address %s\n", addr2string(gsa, addrlen)); return; } /* send multicast */ #ifdef WIN32 if (sendto(s, outbuf, outcnt, 0, gsa, addrlen) < 0) err("sendto"); #else msgh.msg_name = (void *)gsa; if (sendmsg(s, &msgh, 0) < 0) err("sendto"); #endif } void sethops(int s6, int s4, int hops) { #ifdef __sun uint8_t mcttl = hops; #else int mcttl = hops; #endif int ttl = hops; int hopcount = hops; if (s6 >= 0) { if (setsockopt(s6, IPPROTO_IPV6, IPV6_UNICAST_HOPS, (char *)&hopcount, sizeof(hopcount)) == -1) err("setsockopt IPV6_UNICAST_HOPS"); if (setsockopt(s6, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, (char *)&hopcount, sizeof(hopcount)) == -1) err("setsockopt IPV6_MULTICAST_HOPS"); } if (s4 < 0) return; if (setsockopt(s4, IPPROTO_IP, IP_TTL, (char *)&ttl, sizeof(ttl)) == -1) err("setsockopt IP_TTL"); if (setsockopt(s4, IPPROTO_IP, IP_MULTICAST_TTL, (char *)&mcttl, sizeof(mcttl)) == -1) err("setsockopt IP_MULTICAST_TTL"); } int setpktinfo(int s, int family) { #ifdef WIN32 return 0; #else int on = 1; switch (family) { case AF_INET: return setsockopt(s, IPPROTO_IP, #ifdef IP_PKTINFO IP_PKTINFO, #else IP_RECVDSTADDR, #endif &on, sizeof(on)); case AF_INET6: return setsockopt(s, IPPROTO_IPV6, #ifdef IPV6_RECVPKTINFO IPV6_RECVPKTINFO, #else IPV6_PKTINFO, #endif &on, sizeof(on)); } return -1; #endif } int main(int argc, char **argv) { struct addrinfo hints, *res, *res0; int e, s, s4 = -1, s6 = -1, max, ndesc; fd_set readfds; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); WSAStartup(wVersionRequested, &wsaData); /* lots of complicated Win32 error checking expected - sigh - */ #endif setvbuf(stdout, NULL, _IONBF, 0); memset(&hints, 0, sizeof(hints)); hints.ai_socktype = SOCK_DGRAM; hints.ai_family = AF_UNSPEC; hints.ai_flags = AI_PASSIVE; if ((e = getaddrinfo(NULL, "4321", &hints, &res0))) { #ifdef WIN32 err("getaddrinfo failed with error code %d", e); #else err("getaddrinfo failed: %s", gai_strerror(e)); #endif } for (res = res0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if (s < 0) { err("socket"); continue; } if (setpktinfo(s, res->ai_family) == -1) { err("setpktinfo"); continue; } #ifdef IPV6_V6ONLY { int on = 1; if ((res->ai_family == AF_INET6) && (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) == -1)) err("setsockopt IPV6_V6ONLY"); } #endif if (bind(s, res->ai_addr, res->ai_addrlen) < 0) { err("bind"); continue; } switch (res->ai_family) { case AF_INET6: s6 = s; break; case AF_INET: s4 = s; break; default: printf("Only supporting IPv4 and IPv6 families\n"); } } freeaddrinfo(res0); max = s4 > s6 ? s4 : s6; if (max == -1) errx("both v4 and v6 binds failed"); sethops(s6, s4, 64); for(;;) { FD_ZERO(&readfds); if (s4 >= 0) FD_SET(s4, &readfds); if (s6 >= 0) FD_SET(s6, &readfds); ndesc = select(max + 1, &readfds, (fd_set *)0, (fd_set *)0, NULL); if (ndesc < 1) errx("select returned < 1"); if (s4 >= 0 && FD_ISSET(s4, &readfds)) respond(s4); if (s6 >= 0 && FD_ISSET(s6, &readfds)) respond(s6); } } ssmping-0.9.1/ssmpingc.c0000644000223200001440000000566410756305436014404 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id: ssmpingc.c,v 1.4 2005/11/29 16:27:26 sv Exp $ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" void errx(char *format, ...) { extern int errno; va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); if (errno) { fprintf(stderr, ": "); perror(NULL); fprintf(stderr, "errno=%d\n", errno); } else fprintf(stderr, "\n"); exit(1); } void err(char *format, ...) { extern int errno; va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); if (errno) { fprintf(stderr, ": "); perror(NULL); fprintf(stderr, "errno=%d\n", errno); } else fprintf(stderr, "\n"); } void setaddr(struct sockaddr_storage *ss, struct sockaddr_storage *group, const char *addr6, const char *addr4) { struct addrinfo hints, *res; int e; memset(&hints, 0, sizeof(hints)); hints.ai_family = ((struct sockaddr *)ss)->sa_family; hints.ai_socktype = SOCK_DGRAM; switch (((struct sockaddr *)ss)->sa_family) { case AF_INET: if ((e = getaddrinfo(addr4, NULL, &hints, &res))) break; ((struct sockaddr_in *)ss)->sin_addr = ((struct sockaddr_in *)res->ai_addr)->sin_addr; if (group) memcpy(&((struct sockaddr_in *)ss)->sin_addr, &((struct sockaddr_in *)group)->sin_addr, 3); return; case AF_INET6: if ((e = getaddrinfo(addr6, NULL, &hints, &res))) break; ((struct sockaddr_in6 *)ss)->sin6_addr = ((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; if (group) memcpy(&((struct sockaddr_in6 *)ss)->sin6_addr, &((struct sockaddr_in6 *)group)->sin6_addr, 12); return; default: fprintf(stderr, "Unsupported address family\n"); exit(1); } /* Only down here if gettaddrinfo failed */ #ifdef WIN32 err("getaddrinfo failed with error code %d", e); #else err("getaddrinfo failed: %s", gai_strerror(e)); #endif } char *addr2string(struct sockaddr *addr, socklen_t len) { static char addr_buf[2][INET6_ADDRSTRLEN]; static int i = 0; i = !i; if (getnameinfo(addr, len, addr_buf[i], sizeof(addr_buf[i]), NULL, 0, NI_NUMERICHOST)) { err("getnameinfo"); return NULL; } return addr_buf[i]; } size_t tlvspace(size_t size) { return size + 2 * sizeof(uint16_t); } char *tlvadd(char *p, uint16_t t, uint16_t l, void *v) { uint16_t tmp; tmp = htons(t); memcpy(p, &tmp, 2); p += 2; tmp = htons(l); memcpy(p, &tmp, 2); p += 2; if (l) memcpy(p, v, l); return p; } char *tlvaddzero(char *p, uint16_t t, uint16_t l) { uint16_t tmp; tmp = htons(t); memcpy(p, &tmp, 2); p += 2; tmp = htons(l); memcpy(p, &tmp, 2); p += 2; if (l) memset(p, 0, l); return p; } ssmping-0.9.1/ssmping.h0000644000223200001440000000564511002120065014217 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id: ssmping.h,v 1.3 2005/10/18 14:50:31 sv Exp $ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include #include #include #include #include #include #include #include #include #include #ifdef WIN32 #include #include #include #include #else #include #include #include #include #include #include #include #endif /* Needed for Solaris 9 */ #ifndef CMSG_LEN #define CMSG_LEN(len) (_CMSG_DATA_ALIGN (sizeof (struct cmsghdr)) + (len)) #endif #ifndef IPV6_V6ONLY #ifdef linux #define IPV6_V6ONLY 26 #endif #endif #define SSMMODE 1 #define ASMMODE 2 #define FIRSTMODE 3 #define SSMPING_VERSIONSTRING "0.9.1 (20080418)" #define SSMPING_SERVERVERSIONSTRING "0.9.1 (20080418) [asm][size]" #define SSMPING_REQUEST 'Q' #define SSMPING_REPLY 'A' #define SSMPING_PID 1 #define SSMPING_SEQ 2 #define SSMPING_TIMESTAMP 3 #define SSMPING_GROUP 4 #define SSMPING_RQVER 5 #define SSMPING_VER 6 #define SSMPING_REPLYSIZE 7 #define SSMPING_PAD 8 #define SOCKADDR_SIZE(addr) (addr.ss_family == AF_INET ? \ sizeof(struct sockaddr_in) : \ sizeof(struct sockaddr_in6)) struct ssmpingdata { uint32_t pid; uint32_t seq; struct timeval timestamp; }; void errx(char *, ...); void err(char *, ...); void gettime(struct timeval *); void timediff(struct timeval *, struct timeval *, struct timeval *); int timecmp(struct timeval *, struct timeval *); void setport(struct sockaddr *, int); void setaddr(struct sockaddr_storage *, struct sockaddr_storage *, const char *, const char *); char *addr2string(struct sockaddr *, socklen_t); size_t tlvspace(size_t); char *tlvadd(char *, uint16_t, uint16_t, void *); char *tlvaddzero(char *, uint16_t, uint16_t); void parseargs(int, char **, int, int *, int *, uint16_t *, uint32_t *, int *, char **, char **, uint16_t *, uint16_t *, char **); int doit(int, int, int, int, int, struct sockaddr_storage *, struct sockaddr_storage *, char *); int names2addrsocks(int *, int *, const char *, const char *, const char *, int *, struct sockaddr_storage *, struct sockaddr_storage *); void prep_sock(int, int); void findsrc(struct sockaddr *, struct sockaddr *); int recvfromhopstime(int, void *, size_t, int, struct sockaddr *, socklen_t *, int32_t *, struct timeval *, char *); char *addr2string(struct sockaddr *, socklen_t); void joinchannel(int, struct sockaddr *, struct sockaddr *, uint32_t, struct sockaddr *); void joingroup(int, struct sockaddr *, uint32_t, struct sockaddr *); ssmping-0.9.1/ssmping.c0000644000223200001440000000513710756305436014234 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id: ssmping.c,v 1.22 2005/11/29 16:27:26 sv Exp $ * * Contributions: * Solaris support by Alexander Gall * Initial Windows support by Nick Lamb * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" extern int optind; extern char *optarg; int main(int argc, char **argv) { int family, count, ver, us, ms; char *pingee, *group, source[INET6_ADDRSTRLEN]; uint16_t size; uint32_t intface; struct sockaddr_storage name, ucaddr, mcaddr, grpaddr; size_t namelen; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); WSAStartup(wVersionRequested, &wsaData); /* lots of complicated Win32 error checking expected - sigh - */ #endif parseargs(argc, argv, SSMMODE, &family, &ver, &size, &intface, &count, &pingee, &group, NULL, NULL, NULL); if (names2addrsocks(&us, &ms, pingee, group, "4321", &family, &ucaddr, &mcaddr)) errx("name2addrsocks failed"); prep_sock(family, us); prep_sock(family, ms); setvbuf(stdout, NULL, _IONBF, 0); findsrc((struct sockaddr *)&name, (struct sockaddr *)&ucaddr); namelen = SOCKADDR_SIZE(name); setport((struct sockaddr *)&name, 0); if (bind(us, (struct sockaddr *)&name, namelen) < 0) errx("bind"); if (connect(us, (struct sockaddr *)&ucaddr, namelen) < 0) errx("connect"); if (getsockname(us, (struct sockaddr *)&name, &namelen) == -1) errx("getsockname"); grpaddr = name; setaddr(&grpaddr, group ? &mcaddr : NULL, "ff3e::4321:1234", "232.43.211.234"); #ifdef WIN32 { struct sockaddr_storage any = name; setaddr(&any, NULL, "::", "0.0.0.0"); if (bind(ms, (struct sockaddr *)&any, namelen) < 0) errx("bind [ANY]"); } #else if (bind(ms, (struct sockaddr *)&grpaddr, namelen) < 0) errx("bind [multicast]"); #endif /* using name to specify interface is wrong, only problem for old API */ joinchannel(ms, (struct sockaddr *)&ucaddr, (struct sockaddr *)&grpaddr, intface, (struct sockaddr *)&name); strcpy(source, addr2string((struct sockaddr *)&ucaddr, namelen)); printf("ssmping joined (S,G) = (%s,%s)\n", source, addr2string((struct sockaddr *)&grpaddr, namelen)); printf("pinging S from %s\n", addr2string((struct sockaddr *)&name, namelen)); return doit(ver, size, count, us, ms, &ucaddr, &grpaddr, source); } ssmping-0.9.1/ssmping.10000644000223200001440000000320210756305436014141 0ustar venaasusers.\" Copyright (C) 2005, 2006 Stig Venaas .\" Initial man page by Mickael Hoerdt .TH ssmping "1" "User Manuals" .SH NAME ssmping \- check if you can receive IPv4/IPv6 multicast data from an internet host .SH SYNOPSIS .B ssmping [ .B \-46v ] [ .B \-I .I interface ] [ .B \-c .I count ] [ .B \-s .I size ] .I host .sp .B ssmpingd .SH DESCRIPTION .B ssmping and .B ssmpingd are network level multicast management tools that can be used to check whether one can receive multicast packets via SSM from a host. The host target given to .B ssmping must run the .B ssmpingd daemon, which listens on UDP port .B 4321 for IPv4 and IPv6 unicast requests. When it receives one, it responds to a well known SSM multicast group which .B ssmping just have joined. Depending on whether the request was made with IPv4 or IPv6, the group is .B 232.43.211.234 or .B ff3e::4321:1234 respectively. .SH OPTIONS For .B ssmpingd there are no options. For .B ssmping the options are as follows. .TP .B \-4 Force IPv4 .TP .B \-6 Force IPv6 .TP .B \-v Print client and server version information. .TP \fB-I\fR \fIinterface\fR Interface to join on .TP \fB-c\fR \fIcount\fR Stop after sending (and receiving) .I count requests (and replies) .TP \fB-s\fR \fIsize\fR Request replies to have a size of .I size bytes .SH SEE ALSO asmping(1) a tool for checking whether can receive ASM. .TP dbeacon(1) a distributed beacon multicast implementation. .SH BUGS Please report them to Stig Venaas , the author of this tool. .SH HISTORY \fBssmping\fR and \fBssmpingd\fR were developed by Stig Venaas during the early days of the m6bone, the IPv6 multicast backbone. ssmping-0.9.1/mcfirst.c0000644000223200001440000001100410756305436014211 0ustar venaasusers/* * Copyright (C) 2005, 2006 Stig Venaas * $Id:$ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" extern int optind; extern char *optarg; int main(int argc, char **argv) { int famarg, family, ver, s, ndesc, cnt, count, countarg; char *addr1, *addr2, *srv, recvbuf[65535]; uint16_t runtime, rate; uint32_t intface; int32_t hops; struct sockaddr_storage ucaddr, mcaddr; size_t namelen, recvbuflen; uint32_t firstbytes, bytes; struct timeval now, rcvtime, firsttime, endtime, jointime, tstamp, diff; fd_set readfds; struct sockaddr_storage from; socklen_t fromlen = sizeof(from); double msecs; gettime(&endtime); #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); WSAStartup(wVersionRequested, &wsaData); /* lots of complicated Win32 error checking expected - sigh - */ #endif parseargs(argc, argv, FIRSTMODE, &famarg, &ver, NULL, &intface, &countarg, &addr1, &addr2, &runtime, &rate, &srv); if (runtime) endtime.tv_sec += runtime; family = famarg; /* addr2 next addr1 in order to request mc if only one arg */ if (names2addrsocks(&s, NULL, addr2, addr1, srv, &family, &ucaddr, &mcaddr)) { if (addr2) errx("Failed to create socket for %s %s", addr1, addr2); else errx("Failed to create socket for %s", addr1); } prep_sock(family, s); setvbuf(stdout, NULL, _IONBF, 0); namelen = (mcaddr.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)); #ifdef WIN32 { struct sockaddr_storage any = mcaddr; setaddr(&any, NULL, "::", "0.0.0.0"); if (bind(s, (struct sockaddr *)&any, namelen) < 0) errx("bind [INADDR_ANY]"); } #else if (bind(s, (struct sockaddr *)&mcaddr, namelen) < 0) errx("bind [multicast]"); #endif /* using name to specify interface is wrong, only problem for old API */ recvbuflen = sizeof(recvbuf); if (addr2) { joinchannel(s, (struct sockaddr *)&ucaddr, (struct sockaddr *)&mcaddr, intface, NULL); printf("mcfirst joined (S,G) = (%s,%s)\n", addr2string((struct sockaddr *)&ucaddr, namelen), addr2string((struct sockaddr *)&mcaddr, namelen)); } else { joingroup(s, (struct sockaddr *)&mcaddr, intface, NULL); printf("mcfirst joined (*,G) = (*,%s)\n", addr2string((struct sockaddr *)&mcaddr, namelen)); } gettime(&jointime); if (!runtime && !countarg) countarg = 1; bytes = 0; for (count = 0; !countarg || count < countarg; count++) { for(;;) { FD_ZERO(&readfds); FD_SET(s, &readfds); gettime(&now); timediff(&diff, &now, &endtime); ndesc = select(s + 1, &readfds, (fd_set *)0, (fd_set *)0, runtime ? &diff : NULL); gettime(&now); if (runtime && (timecmp(&endtime, &now) <= 0)) goto done; if (ndesc < 1) continue; cnt = recvfromhopstime(s, (void *)&recvbuf, recvbuflen, 0, (struct sockaddr *)&from, &fromlen, &hops, &tstamp, NULL); if (cnt == -1) { err("recv failed"); continue; } break; } rcvtime = tstamp.tv_sec ? tstamp : now; if (!count) { firsttime = rcvtime; firstbytes = cnt; } bytes += cnt; if (!rate) { fromlen = from.ss_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); timediff(&diff, &jointime, &rcvtime); printf("Received %d bytes from %s after %ld.%03ld ms (ttl/hops %d)\n", cnt, addr2string((struct sockaddr *) &from, fromlen), diff.tv_sec * 1000 + diff.tv_usec / 1000, diff.tv_usec % 1000, hops); } } done: timediff(&diff, &jointime, &rcvtime); printf("%d bytes (payload) and %d packets received in %ld.%03ld seconds\n", bytes, count, diff.tv_sec, (diff.tv_usec + 500) / 1000); if (count < 2) return !count; timediff(&diff, &firsttime, &rcvtime); msecs = (double)diff.tv_sec * 1000 + (double)diff.tv_usec / 1000; if (!msecs) return !count; bytes -= firstbytes; printf("Average rate: %.3f kbits of payload per second\n", (double)bytes / msecs * 8); /* estimate bytes including minimum packet headers */ bytes += (count - 1) * (mcaddr.ss_family == AF_INET ? 28 : 48); printf("Estimated average rate including all headers: %.3f kbits per second\n", (double)bytes / msecs * 8); return !count; } ssmping-0.9.1/mcfirst.10000644000223200001440000000274010756305436014136 0ustar venaasusers.\" Copyright (C) 2006 Stig Venaas .TH mcfirst "1" "User Manuals" .SH NAME mcfirst \- check if you can receive IPv4/IPv6 multicast .SH SYNOPSIS .B mcfirst [ .B \-46vr ] [ .B \-I .I interface ] [ .B \-c .I count ] [ .B \-t .I time ] [ .I source ] .I group .I port .SH DESCRIPTION .B mcfirst can be used to check whether one can receive multicast packets from a host. The host may send any type of multicast packets, any application, IPv4 or IPv6, ASM or SSM. .B mcfirst joins the specified (source) and group, and listens to the specified port. .B mcfirst will by default exit when the first packet is received, and print how long it waited. .SH OPTIONS The options are as follows. .TP .B \-4 Force IPv4 .TP .B \-6 Force IPv6 .TP .B \-v Print version .TP .B \-r Print rate information only .TP \fB-I\fR \fIinterface\fR Interface to join on .TP \fB-c\fR \fIcount\fR Stop after receiving .I count packets. Default is 1 unless time limit is specified .TP \fB-t\fR \fItime\fR Exit after .I time seconds. Default is to exit after the first packet. If both .I count and .I time are specified, mcfirst will exit as soon as one of them is satisfied. .SH SEE ALSO ssmping(1) a tool for checking whether can receive SSM. .TP dbeacon(1) a distributed beacon multicast implementation. .SH BUGS Please report them to Stig Venaas , the author of this tool. .SH HISTORY \fBmcfirst\fR was developed by Stig Venaas during the early days of the m6bone, the IPv6 multicast backbone. ssmping-0.9.1/joingrp.c0000644000223200001440000000357110756305436014224 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id:$ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" void joingroup(int s, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) { int e; #ifdef MCAST_JOIN_GROUP int level; socklen_t addrlen; struct group_req greq; #endif if (grp && ifaddr && ifaddr->sa_family != grp->sa_family) { fprintf(stderr, "joingroup failed, group and interface must be of same address family\n"); exit(1); } switch (grp->sa_family) { case AF_INET: #ifdef MCAST_JOIN_GROUP addrlen = sizeof(struct sockaddr_in); level = IPPROTO_IP; #else { struct ip_mreq mreq; memset(&mreq, 0, sizeof(mreq)); mreq.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr; if (ifaddr) mreq.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr; e = setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char *)&mreq, sizeof(mreq)); } #endif break; case AF_INET6: #ifdef MCAST_JOIN_GROUP addrlen = sizeof(struct sockaddr_in6); level = IPPROTO_IPV6; #else { struct ipv6_mreq mreq6; memset(&mreq6, 0, sizeof(mreq6)); mreq6.ipv6mr_multiaddr = ((struct sockaddr_in6 *)grp)->sin6_addr; mreq6.ipv6mr_interface = intface; e = setsockopt(s, IPPROTO_IPV6, IPV6_JOIN_GROUP, (char *)&mreq6, sizeof(mreq6)); } #endif break; default: fprintf(stderr, "joingroup failed, unsupported address family\n"); exit(1); } #ifdef MCAST_JOIN_GROUP memset(&greq, 0, sizeof(greq)); memcpy(&greq.gr_group, grp, addrlen); greq.gr_interface = intface; e = setsockopt(s, level, MCAST_JOIN_GROUP, (char *)&greq, sizeof(greq)); #endif if (e < 0) errx("Failed to join multicast group"); } ssmping-0.9.1/joinch.c0000644000223200001440000000523410756305436014024 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id:$ * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" #ifndef MCAST_JOIN_SOURCE_GROUP #ifdef WIN32 /* Only useful on Vista */ #define MCAST_JOIN_SOURCE_GROUP 45 #endif #ifdef linux #define MCAST_JOIN_SOURCE_GROUP 46 #endif struct group_source_req { uint32_t gsr_interface; /* interface index */ struct sockaddr_storage gsr_group; /* group address */ struct sockaddr_storage gsr_source; /* source address */ }; #endif void joinchannel(int s, struct sockaddr *src, struct sockaddr *grp, uint32_t intface, struct sockaddr *ifaddr) { #ifdef MCAST_JOIN_SOURCE_GROUP int level; socklen_t addrlen; #ifdef WIN32 struct ip_mreq_source imsr; #endif struct group_source_req gsreq; if (src->sa_family != grp->sa_family) { fprintf(stderr, "joinchannel failed, source and group must be of same address family\n"); exit(1); } if (ifaddr && ifaddr->sa_family != grp->sa_family) { fprintf(stderr, "joinchannel failed, group and interface must be of same address family\n"); exit(1); } switch (grp->sa_family) { case AF_INET: addrlen = sizeof(struct sockaddr_in); level = IPPROTO_IP; break; case AF_INET6: addrlen = sizeof(struct sockaddr_in6); level = IPPROTO_IPV6; break; default: fprintf(stderr, "joinchannel failed, unsupported address family\n"); exit(1); } memset(&gsreq, 0, sizeof(gsreq)); memcpy(&gsreq.gsr_source, src, addrlen); memcpy(&gsreq.gsr_group, grp, addrlen); gsreq.gsr_interface = intface; #ifndef WIN32 if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) < 0) errx("Failed to join multicast channel"); #else if (setsockopt(s, level, MCAST_JOIN_SOURCE_GROUP, (char *)&gsreq, sizeof(gsreq)) >= 0) return; if (level != IPPROTO_IP) errx("Failed to join multicast channel"); /* For Windows XP the above setsockopt fails, below works for IPv4 * While for Windows Vista the above should work */ memset(&imsr, 0, sizeof(imsr)); imsr.imr_sourceaddr = ((struct sockaddr_in *)src)->sin_addr; imsr.imr_multiaddr = ((struct sockaddr_in *)grp)->sin_addr; imsr.imr_interface = ((struct sockaddr_in *)ifaddr)->sin_addr; if (setsockopt(s, level, IP_ADD_SOURCE_MEMBERSHIP, (char *)&imsr, sizeof(imsr)) < 0) errx("Failed to join multicast channel"); #endif #else errx("Not built with SSM support, failed to join multicast channel"); #endif } ssmping-0.9.1/asmping.c0000644000223200001440000000516510756305436014213 0ustar venaasusers/* * Copyright (C) 2005 Stig Venaas * $Id: asmping.c,v 1.4 2005/11/29 16:27:26 sv Exp $ * * Contributions: * Solaris support by Alexander Gall * Initial Windows support by Nick Lamb * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. */ #include "ssmping.h" extern int optind; extern char *optarg; int main(int argc, char **argv) { int famarg, family, count, ver, us, ms; char *pingee, *group, source[INET6_ADDRSTRLEN]; uint16_t size; uint32_t intface; struct sockaddr_storage name, ucaddr, mcaddr, grpaddr; socklen_t namelen; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD( 2, 0 ); WSAStartup(wVersionRequested, &wsaData); /* lots of complicated Win32 error checking expected - sigh - */ #endif parseargs(argc, argv, ASMMODE, &famarg, &ver, &size, &intface, &count, &pingee, &group, NULL, NULL, NULL); family = famarg; if (names2addrsocks(&us, &ms, pingee, group, "4321", &family, &ucaddr, &mcaddr)) errx("Failed to create socket for %s", group); prep_sock(family, us); prep_sock(family, ms); setvbuf(stdout, NULL, _IONBF, 0); findsrc((struct sockaddr *)&name, (struct sockaddr *)&ucaddr); namelen = SOCKADDR_SIZE(name); setport((struct sockaddr *)&name, 0); if (bind(us, (struct sockaddr *)&name, namelen) < 0) errx("bind"); if (connect(us, (struct sockaddr *)&ucaddr, namelen) < 0) errx("connect"); if (getsockname(us, (struct sockaddr *)&name, &namelen) == -1) errx("getsockname"); grpaddr = name; setaddr(&grpaddr, group ? &mcaddr : NULL, "ff3e::4321:1234", "232.43.211.234"); #ifdef WIN32 { struct sockaddr_storage any = name; setaddr(&any, NULL, "::", "0.0.0.0"); if (bind(ms, (struct sockaddr *)&any, namelen) < 0) errx("bind [INADDR_ANY]"); } #else if (bind(ms, (struct sockaddr *)&grpaddr, namelen) < 0) errx("bind [multicast]"); #endif /* using name to specify interface is wrong, only problem for old API */ joingroup(ms, (struct sockaddr *)&grpaddr, intface, (struct sockaddr *)&name); strcpy(source, addr2string((struct sockaddr *)&ucaddr, namelen)); printf("asmping joined (S,G) = (*,%s)\n", addr2string((struct sockaddr *)&grpaddr, namelen)); printf("pinging %s from %s\n", source, addr2string((struct sockaddr *)&name, namelen)); return doit(ver, size, count, us, ms, &ucaddr, &grpaddr, source); } ssmping-0.9.1/asmping.10000644000223200001440000000331510756305436014124 0ustar venaasusers.\" Copyright (C) 2005 Stig Venaas .\" $Id: asmping.1,v 1.1 2005/10/18 14:50:31 sv Exp $ .TH asmping "1" "User Manuals" .SH NAME asmping \- check if you can receive IPv4/IPv6 multicast data from an internet host .SH SYNOPSIS .B asmping [ .B \-46v ] [ .B \-I .I interface ] [ .B \-c .I count ] [ .B \-s .I size ] .I group .I host .sp .B ssmpingd .SH DESCRIPTION .B asmping and .B ssmpingd are network level multicast management tools that can be used to check whether one can receive multicast packets via ASM from a host. The host target given to .B asmping must run the .B ssmpingd daemon, which listens on UDP port .B 4321 for IPv4 and IPv6 unicast requests. When it receives one, it responds to the specified multicast group which .B asmping just have joined. Note that one can not use arbitrary groups. Independent of what group is specified, the last quarter of the address is forced to be .B 234 or .B ::4321:1234 for IPv4 or IPv6 respectively. .SH OPTIONS For .B ssmpingd there are no options. For .B asmping the options are as follows. .TP .B \-4 Force IPv4 .TP .B \-6 Force IPv6 .TP .B \-v Print client and server version information. .TP \fB-I\fR \fIinterface\fR Interface to join on .TP \fB-c\fR \fIcount\fR Stop after sending (and receiving) .I count requests (and replies) .TP \fB-s\fR \fIsize\fR Request replies to have a size of .I size bytes .SH SEE ALSO ssmping(1) a tool for checking whether can receive SSM. .TP dbeacon(1) a distributed beacon multicast implementation. .SH BUGS Please report them to Stig Venaas , the author of this tool. .SH HISTORY \fBasmping\fR and \fBssmpingd\fR were developed by Stig Venaas during the early days of the m6bone, the IPv6 multicast backbone. ssmping-0.9.1/README0000644000223200001440000001014510756305436013263 0ustar venaasusersssmping/asmping/ssmpingd/mcfirst README Introduction ssmping is a tool for checking whether a host can receive SSM from another. If a host runst ssmpingd, users on other hosts can check that they receive from this host by running the ssmping tool. asmping is similar to ssmping, but checks for ASM rather than SSM. This package also contains a tool called mcfirst. How it works ssmpingd listens for ssmping requests at UDP port 4321, both IPv4 and IPv6. ssmping is run as "ssmping host". ssmping will look up addresses for hostname if necessary (both IPv4 and IPv6 addresses) and then join (S,G) where S is the IP address, and G is either 232.43.211.234 for IPv4 or ff3e::4321:1234 for IPv6. Next it will until interrupted, send a unicast UDP ping request to the host once per second. If the host is running ssmpingd, it will respond by sending the request packet back (only changing type from request to reply). The reply is sent back both by unicast and to the multicast group G that the client joined. asmping works pretty much like ssmping, but the group to use must be specified. Note that the group will be forced to end with 234 for IPv4, and ::4321:1234 for IPv6. Example ssmping output: ssmping joined (S,G) = (2001:700:1:7:290:27ff:fe22:7186,ff3e::4321:1234) pinging S from 2001:630:d0:111:250:fcff:fe6a:42b3 unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=0 dist=20 time=56.5ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=1 dist=20 time=58.6ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=2 dist=20 time=57.1ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=3 dist=20 time=58.5ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=4 dist=20 time=74.0ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=5 dist=20 time=60.7ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=6 dist=20 time=56.5ms multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=6 dist=12 time=60.9ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=7 dist=20 time=61.1ms multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=7 dist=12 time=64.1ms unicast from 2001:700:1:7:290:27ff:fe22:7186, seq=8 dist=20 time=70.9ms multicast from 2001:700:1:7:290:27ff:fe22:7186, seq=8 dist=12 time=73.2ms This shows that it took about 6s for the multicast tree to be established. The first 6 multicast packets got lost. It also shows the round-trip time for the unicast and multicat (note that the multicast is really unicast in one direction). This shows here that there is roughly 3-4ms additional delay for the multicat packets. It also shows that the unicast packets have travelled 20 hops, while multicast only 12 hops. This shows that there probably is some tunneling for multicast. This is measured by having ssmpingd send all packets with a TTL/hop-limit of 64. Building On most systems you can just type "make". On Solaris or Windows try one of the alternate Makefiles. If your system does not support SSM, you can still use asmping and ssmpingd. If ssmping build fails, try "make asmping" and "make ssmpingd". Usage ssmpingd is run without arguments. ssmping takes hostname or IP address as argument. asmping takes group and hostname/address as arguments. See man pages for details. mcfirst mcfirst is a tool to check whether you can receive a given multicast transmission. It supports both ASM and SSM, and IPv4 and IPv6. You run it specifying multicast group (and source if SSM) and port number. It will then run until it receives a single multicast packet, and tell you how long it took. Optionally you may specify how many packets and/or for how many seconds it shall run. If you specify how long to run, it will also tell you how many bits and packets per second were received. This tool will be built together with the ssmping tools. Credits The ssmping idea was proposed by Pavan Namburi, Kamil Sarac and Kevin C. Almeroth in the paper http://www.utdallas.edu/~ksarac/research/publications/CIIT04-1.pdf I was also inspired to work on this from discussions with Mickael Hoerdt who has contributed with several ideas. License See top of the individual source files. Bugs/feedback I would be happy for any feedback. 2006-06-05 Stig Venaas ssmping-0.9.1/Makefile-win320000644000223200001440000000144110756305436015002 0ustar venaasusersCC=/opt/xmingw/bin/i386-mingw32msvc-gcc CFLAGS=-Wall -I/opt/xmingw/i386-mingw32msvc/include LIBPATH = /opt/xmingw/i386-mingw32msvc/lib OBJ = ssmpngcl.o ssmpingc.o all: ssmping asmping ssmpingd mcfirst ssmping: $(OBJ) joinch.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a asmping: $(OBJ) joingrp.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a mcfirst: $(OBJ) joinch.o joingrp.o $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a ssmpingd: $(OBJ) $(LIBPATH)/libwsock32.a $(LIBPATH)/libws2_32.a $(LIBPATH)/libdnsapi.a clean: rm -f $(OBJ) joinch.o joingrp.o ssmping asmping ssmpingd mcfirst install: ssmping asmping ssmpingd mcfirst mv ssmping ssmping.exe mv asmping asmping.exe mv ssmpingd ssmpingd.exe mv mcfirst mcfirst.exe ssmping-0.9.1/Makefile-solaris90000644000223200001440000000121110756305436015600 0ustar venaasusersPREFIX ?= /usr/local CFLAGS ?= -D_POSIX_C_SOURCE -D__EXTENSIONS__ -D_XPG4_2 LDFLAGS ?= -lsocket -lnsl all: asmping ssmpingd mcfirst OBJ = ssmpngcl.o ssmpingc.o ssmping: $(OBJ) joinch.o asmping: $(OBJ) joingrp.o ssmpingd: $(OBJ) mcfirst: $(OBJ) joinch.o joingrp.o install: asmping ssmpingd mcfirst install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1 install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1 clean: rm -f $(OBJ) joinch.o joingrp.o asmping ssmpingd mcfirst ssmping-0.9.1/Makefile-solaris100000644000223200001440000000131010756305436015650 0ustar venaasusersPREFIX ?= /usr/local LDFLAGS ?= -lsocket -lnsl all: ssmping asmping ssmpingd mcfirst OBJ = ssmpngcl.o ssmpingc.o ssmping: $(OBJ) joinch.o asmping: $(OBJ) joingrp.o ssmpingd: $(OBJ) mcfirst: $(OBJ) joinch.o joingrp.o install: ssmping asmping ssmpingd mcfirst install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1 install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1 install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1 clean: rm -f $(OBJ) ssmping asmping ssmpingd mcfirst ssmping-0.9.1/Makefile-bsd0000644000223200001440000000152210756305436014610 0ustar venaasusersPREFIX ?= /usr/local all: ssmping asmping ssmpingd mcfirst OBJ = ssmpngcl.o ssmpingc.o joinch.o joingrp.o ssmping: $(OBJ) $(CC) $(CFLAGS) $(OBJ) -o ssmping ssmping.c asmping: $(OBJ) $(CC) $(CFLAGS) $(OBJ) -o asmping asmping.c ssmpingd: $(OBJ) $(CC) $(CFLAGS) $(OBJ) -o ssmpingd ssmpingd.c mcfirst: $(OBJ) $(CC) $(CFLAGS) $(OBJ) -o mcfirst mcfirst.c install: ssmping asmping ssmpingd mcfirst install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1 install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1 install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1 clean: rm -f $(OBJ) ssmping asmping ssmpingd mcfirst ssmping-0.9.1/Makefile0000644000223200001440000000127710756305436014051 0ustar venaasusersPREFIX ?= /usr/local all: ssmping asmping ssmpingd mcfirst OBJ = ssmpngcl.o ssmpingc.o ssmping: $(OBJ) joinch.o asmping: $(OBJ) joingrp.o mcfirst: $(OBJ) joinch.o joingrp.o ssmpingd: $(OBJ) install: ssmping asmping ssmpingd mcfirst install -D ssmping $(DESTDIR)$(PREFIX)/bin/ssmping install -D asmping $(DESTDIR)$(PREFIX)/bin/asmping install -D ssmpingd $(DESTDIR)$(PREFIX)/bin/ssmpingd install -D mcfirst $(DESTDIR)$(PREFIX)/bin/mcfirst install -D ssmping.1 $(DESTDIR)$(PREFIX)/man/man1/ssmping.1 install -D asmping.1 $(DESTDIR)$(PREFIX)/man/man1/asmping.1 install -D mcfirst.1 $(DESTDIR)$(PREFIX)/man/man1/mcfirst.1 clean: rm -f $(OBJ) joinch.o joingrp.o ssmping asmping ssmpingd mcfirst