1 #include <sys/types.h> 2 #include <sys/socket.h> 3 4 #include <arpa/inet.h> 5 #include <net/if.h> 6 #include <netinet/in.h> 7 8 #include <err.h> 9 #include <stdint.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 15 static void 16 usage(const char *cmd) 17 { 18 fprintf(stderr, "%s -p port -d dst (-i addr [-m] | -I iface) " 19 "[-P bind_port]\n", cmd); 20 exit(1); 21 } 22 23 int 24 main(int argc, char *argv[]) 25 { 26 struct sockaddr_in dst, local_in; 27 struct in_addr iface, mcast_if; 28 int s, opt, n, loop = 0, use_mreq = 0, iface_idx; 29 uint8_t buf[18]; 30 socklen_t mcast_if_len; 31 char mcast_if_str[INET_ADDRSTRLEN]; 32 33 memset(&dst, 0, sizeof(dst)); 34 dst.sin_family = AF_INET; 35 36 memset(&local_in, 0, sizeof(local_in)); 37 local_in.sin_family = AF_INET; 38 39 memset(&iface, 0, sizeof(iface)); 40 iface_idx = -1; 41 42 while ((opt = getopt(argc, argv, "I:P:d:i:mp:")) != -1) { 43 switch (opt) { 44 case 'I': 45 iface_idx = if_nametoindex(optarg); 46 break; 47 48 case 'P': 49 local_in.sin_port = strtol(optarg, NULL, 10); 50 local_in.sin_port = htons(local_in.sin_port); 51 break; 52 53 case 'd': 54 if (inet_pton(AF_INET, optarg, &dst.sin_addr) <= 0) 55 usage(argv[0]); 56 break; 57 58 case 'i': 59 if (inet_pton(AF_INET, optarg, &iface) <= 0) 60 usage(argv[0]); 61 break; 62 63 case 'm': 64 use_mreq = 1; 65 break; 66 67 case 'p': 68 dst.sin_port = strtol(optarg, NULL, 10); 69 dst.sin_port = htons(dst.sin_port); 70 break; 71 72 default: 73 usage(argv[0]); 74 } 75 } 76 77 if ((iface.s_addr == INADDR_ANY && iface_idx < 0) || 78 dst.sin_addr.s_addr == INADDR_ANY || dst.sin_port == 0) 79 usage(argv[0]); 80 81 s = socket(AF_INET, SOCK_DGRAM, 0); 82 if (s < 0) 83 err(2, "socket failed"); 84 85 if (iface_idx >= 0) { 86 struct ip_mreqn mreqn; 87 88 fprintf(stderr, "ip_mreqn mcast_if ifindex %d\n", iface_idx); 89 memset(&mreqn, 0, sizeof(mreqn)); 90 mreqn.imr_address = iface; 91 mreqn.imr_ifindex = iface_idx; 92 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 93 &mreqn, sizeof(mreqn)) < 0) 94 err(2, "setsockopt IP_MULTICAST_IF ip_mreqn failed"); 95 } else if (use_mreq) { 96 struct ip_mreq mreq; 97 98 fprintf(stderr, "ip_mreq mcast_if\n"); 99 memset(&mreq, 0, sizeof(mreq)); 100 mreq.imr_interface = iface; 101 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 102 &mreq, sizeof(mreq)) < 0) 103 err(2, "setsockopt IP_MULTICAST_IF ip_mreq failed"); 104 } else { 105 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 106 &iface, sizeof(iface)) < 0) 107 err(2, "setsockopt IP_MULTICAST_IF inaddr failed"); 108 } 109 110 mcast_if_len = sizeof(mcast_if); 111 if (getsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, 112 &mcast_if, &mcast_if_len) < 0) 113 err(2, "getsockopt IP_MULTICAST_IF failed"); 114 fprintf(stderr, "ifindex %s\n", inet_ntop(AF_INET, &mcast_if, 115 mcast_if_str, sizeof(mcast_if_str))); 116 117 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, 118 &loop, sizeof(loop)) < 0) 119 err(2, "setsockopt IP_MULTICAST_LOOP failed"); 120 121 if (local_in.sin_port != 0) { 122 local_in.sin_addr = iface; 123 if (bind(s, (const struct sockaddr *)&local_in, 124 sizeof(local_in)) < 0) 125 err(2, "bind failed"); 126 } 127 128 n = sendto(s, buf, sizeof(buf), 0, 129 (const struct sockaddr *)&dst, sizeof(dst)); 130 if (n < 0) 131 err(2, "sendto failed"); 132 else if (n < (int)sizeof(buf)) 133 errx(2, "sent truncated data %d", n); 134 135 exit(0); 136 } 137