/*** * * msft - test a IGMPv3 host stack, using the protocol dependent (ipv4) api * * Usage: msft [filename] ; '?' shows help * * File: msft.c * Date: 12/4/2000 * Auth: wilbertdg@hetnet.nl * * * Remarks: * In order to compile, your OS needs to support the 'Socket Interface Extensions * for Multicast Source Filters' as specified in 'draft-ietf-idmr-msf-api-01.txt'. * ***/ #define MAX_ADDRS 20 #include #include #include #include #ifndef WIN32 #include #include #include #include #include #include #include #else #define WIN32_LEAN_AND_MEAN #include #include #include #include #define SIOCSIPMSFILTER SIO_SET_MULTICAST_FILTER #define SIOCGIPMSFILTER SIO_GET_MULTICAST_FILTER #define EADDRNOTAVAIL WSAEADDRNOTAVAIL #define isblank(x) (((x) != ' ') && ((x) != '\t') && ((x) != '\n')) #endif /* * Mapping from error to symblic name */ static struct err_entry { int err_no; char *err_name; } err_map [] = { { EINVAL, "EINVAL" }, { ENOENT, "ENOENT" }, { ENOMEM, "ENOMEM" }, { EADDRNOTAVAIL, "EADDRNOTAVAIL" }, { 0, "ENOERR" } }; /* * Prototypes */ void process_file(char *, int); void process_cmd(char*, int, FILE *fp); char *error_2_name(int err); void usage(); int comp_in_addr(const void *, const void *); /* * main() */ main( argc, argv ) int argc; char **argv; { #ifndef WIN32 int s; #else SOCKET s; #endif int i; char line[80], *p; #ifdef WIN32 WORD wVersionRequested; WSADATA wsaData; wVersionRequested = MAKEWORD(2, 2); if ((WSAStartup(wVersionRequested, &wsaData)) != 0) { printf("failed to initialize winsock\n"); exit(1); } #endif /* Create the socket that's used for all commands */ s = socket(AF_INET, SOCK_DGRAM, 0); #ifndef WIN32 if (s == -1) { #else if (s == INVALID_SOCKET) { #endif printf("failed to create a socket\n"); exit(1); } if (argc < 2) { /* Process commands until user tells to quit */ while (1) { if (fgets(line, sizeof(line), stdin) != NULL) { if (line[0] != 'f') process_cmd(line, s, stdin); else { /* Get the filename */ for (i=1; isblank(line[i]); i++); if ((p = (char*) strchr(line, '\n')) != NULL) *p = '\0'; process_file(&line[i], s); } } } } else { /* Process the commands from a file */ for (i=1; iimsf_multiaddr.s_addr = inet_addr(str1)) == INADDR_NONE) || ((imsfp->imsf_interface.s_addr = inet_addr(str2)) == INADDR_NONE) || (n > MAX_ADDRS)) { printf("-1\n"); break; } imsfp->imsf_fmode = (*cmd == 'i') ? MCAST_INCLUDE : MCAST_EXCLUDE; imsfp->imsf_numsrc = n; for (i=0; iimsf_slist[i].s_addr = inet_addr(str1)) == INADDR_NONE) { printf("-1\n"); return; } } #ifndef WIN32 if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) printf("%s\n", error_2_name(errno)); #else i = WSAIoctl(s, SIOCSIPMSFILTER, (PBYTE) imsfp, IP_MSFILTER_SIZE(n), (PBYTE) imsfp, IP_MSFILTER_SIZE(MAX_ADDRS), &n, NULL, NULL); if (i == SOCKET_ERROR) printf("%s\n", error_2_name(WSAGetLastError())); #endif else printf("%s\n", error_2_name(0)); break; case 't': case 'b': /* Allow or block traffic from a source, using the delta based api */ sscanf(line, "%s %s %s", &str1, &str2, &str3); if (((imrs.imr_multiaddr.s_addr = inet_addr(str1)) == INADDR_NONE) || ((imrs.imr_interface.s_addr = inet_addr(str2)) == INADDR_NONE) || ((imrs.imr_sourceaddr.s_addr = inet_addr(str3)) == INADDR_NONE)) { printf("-1\n"); break; } /* First find out current filter mode */ imsfp = (struct ip_msfilter*) buffer; imsfp->imsf_multiaddr.s_addr = imrs.imr_multiaddr.s_addr; imsfp->imsf_interface.s_addr = imrs.imr_interface.s_addr; imsfp->imsf_numsrc = 5; #ifndef WIN32 if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) { #else if (ioctlsocket((SOCKET) s, SIOCSIPMSFILTER, (unsigned long*) imsfp) == SOCKET_ERROR) { #endif /* It's only okay for 't' to fail */ if (*cmd != 't') { printf("%s\n", error_2_name(errno)); break; } else imsfp->imsf_fmode = MCAST_INCLUDE; } if (imsfp->imsf_fmode == MCAST_EXCLUDE) { /* Any source */ opt = ( *cmd == 't') ? IP_UNBLOCK_SOURCE : IP_BLOCK_SOURCE; } else { /* Controlled source */ opt = ( *cmd == 't') ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP; } #ifndef WIN32 if (setsockopt(s, IPPROTO_IP, opt, &imrs, sizeof(imrs)) == -1) #else if (setsockopt(s, IPPROTO_IP, opt, (char*) &imrs, sizeof(imrs)) == SOCKET_ERROR) #endif printf("%s\n", error_2_name(errno)); else printf("%s\n", error_2_name(0)); break; case 'g': /* Get and show the current filter mode, and the sources in the list */ if ((sscanf(line, "%s %s %d", str1, str2, &n)) != 3) { printf("-1\n"); break; } imsfp = (struct ip_msfilter*) buffer; if (((imsfp->imsf_multiaddr.s_addr = inet_addr(str1)) == INADDR_NONE) || ((imsfp->imsf_interface.s_addr = inet_addr(str2)) == INADDR_NONE) || (n < 0 || n > MAX_ADDRS)) { printf("-1\n"); break; } imsfp->imsf_numsrc = n; #ifndef WIN32 if (ioctl(s, SIOCSIPMSFILTER, imsfp) != 0) { #else i = WSAIoctl(s, SIOCSIPMSFILTER, (PBYTE) imsfp, IP_MSFILTER_SIZE(n), (PBYTE) imsfp, IP_MSFILTER_SIZE(MAX_ADDRS), &n, NULL, NULL); if (i == SOCKET_ERROR) { #endif printf("%s\n", error_2_name(errno)); break; } printf("%s\n", (imsfp->imsf_fmode == MCAST_INCLUDE) ? "include" : "exclude"); printf("%d\n", imsfp->imsf_numsrc); if (n >= imsfp->imsf_numsrc) { n = imsfp->imsf_numsrc; qsort(imsfp->imsf_slist, n, sizeof(struct in_addr), &comp_in_addr); for (i=0; iimsf_slist[i])); } break; case '\n': break; default: break; } } /* * Print usage information */ void usage() { printf("j g.g.g.g i.i.i.i - join IP multicast group\n"); printf("l g.g.g.g i.i.i.i - leave IP multicast group\n"); #ifndef WIN32 printf("a ifname e.e.e.e.e.e - add ether multicast address\n"); printf("d ifname e.e.e.e.e.e - delete ether multicast address\n"); printf("m ifname 1/0 - set/clear ether allmulti flag\n"); printf("p ifname 1/0 - set/clear ether promisc flag\n"); #endif printf("i g.g.g.g i.i.i.i n - set n include mode src filter\n"); printf("e g.g.g.g i.i.i.i n - set n exclude mode src filter\n"); printf("t g.g.g.g i.i.i.i s.s.s.s - allow traffic from src\n"); printf("b g.g.g.g i.i.i.i s.s.s.s - block traffic from src\n"); printf("g g.g.g.g i.i.i.i n - get and show (max n) src filters\n"); printf("f filename - read command(s) from file\n"); printf("s seconds - sleep for some time\n"); printf("q - quit\n"); } /* * Try to translate an error message in the name of the define */ char *error_2_name(int err) { int i; for (i=0; err_map[i].err_no != 0; i++) if (err_map[i].err_no == err) return err_map[i].err_name; return (err != 0) ? "UNKNOWN" : "ENOERR"; } int comp_in_addr(const void *a, const void *b) { return (int) ((struct in_addr*)a)->s_addr - ((struct in_addr*)b)->s_addr; }