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 -m addr -p port (-i addr | -I iface) [-a]\n", cmd); 19 exit(1); 20 } 21 22 static int 23 create_sock(const struct sockaddr_in *in0, const struct in_addr *iface, 24 int iface_idx, int bind_any) 25 { 26 struct sockaddr_in in; 27 int s, on; 28 29 s = socket(AF_INET, SOCK_DGRAM, 0); 30 if (s < 0) 31 err(2, "socket failed"); 32 33 on = 1; 34 if (setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0) 35 err(2, "setsockopt SO_REUSEPORT failed"); 36 37 in = *in0; 38 if (bind_any) 39 in.sin_addr.s_addr = htonl(INADDR_ANY); 40 41 if (bind(s, (const struct sockaddr *)&in, sizeof(in)) < 0) 42 err(2, "bind failed"); 43 44 if (iface_idx < 0) { 45 struct ip_mreq mreq; 46 47 fprintf(stderr, "ip_mreq add_member\n"); 48 memset(&mreq, 0, sizeof(mreq)); 49 mreq.imr_multiaddr = in0->sin_addr; 50 mreq.imr_interface = *iface; 51 if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, 52 &mreq, sizeof(mreq)) < 0) 53 err(2, "setsockopt IP_ADD_MEMBERSHIP ip_mreq failed"); 54 } else { 55 struct ip_mreqn mreqn; 56 57 fprintf(stderr, "ip_mreqn add_member, ifindex %d\n", iface_idx); 58 memset(&mreqn, 0, sizeof(mreqn)); 59 mreqn.imr_multiaddr = in0->sin_addr; 60 mreqn.imr_address = *iface; 61 mreqn.imr_ifindex = iface_idx; 62 if (setsockopt(s, IPPROTO_IP, IP_ADD_MEMBERSHIP, 63 &mreqn, sizeof(mreqn)) < 0) 64 err(2, "setsockopt IP_ADD_MEMBERSHIP ip_mreqn failed"); 65 } 66 67 return s; 68 } 69 70 int 71 main(int argc, char *argv[]) 72 { 73 struct sockaddr_in in; 74 struct in_addr iface; 75 int s1, s2, opt, n, bind_any, iface_idx; 76 uint8_t buf[18]; 77 78 memset(&in, 0, sizeof(in)); 79 in.sin_family = AF_INET; 80 81 memset(&iface, 0, sizeof(iface)); 82 bind_any = 0; 83 iface_idx = -1; 84 85 while ((opt = getopt(argc, argv, "I:ai:m:p:")) != -1) { 86 switch (opt) { 87 case 'I': 88 iface_idx = if_nametoindex(optarg); 89 break; 90 91 case 'a': 92 bind_any = 1; 93 break; 94 95 case 'i': 96 if (inet_pton(AF_INET, optarg, &iface) <= 0) 97 usage(argv[0]); 98 break; 99 100 case 'm': 101 if (inet_pton(AF_INET, optarg, &in.sin_addr) <= 0) 102 usage(argv[0]); 103 break; 104 105 case 'p': 106 in.sin_port = strtol(optarg, NULL, 10); 107 in.sin_port = htons(in.sin_port); 108 break; 109 110 default: 111 usage(argv[0]); 112 } 113 } 114 115 if (in.sin_addr.s_addr == INADDR_ANY || in.sin_port == 0 || 116 (iface.s_addr == INADDR_ANY && iface_idx < 0)) 117 usage(argv[0]); 118 119 s1 = create_sock(&in, &iface, iface_idx, bind_any); 120 s2 = create_sock(&in, &iface, iface_idx, bind_any); 121 122 n = read(s1, buf, sizeof(buf)); 123 if (n < 0) 124 err(2, "read 1 failed"); 125 fprintf(stderr, "read 1 got %d\n", n); 126 127 n = read(s2, buf, sizeof(buf)); 128 if (n < 0) 129 err(2, "read 2 failed"); 130 fprintf(stderr, "read 2 got %d\n", n); 131 132 exit(0); 133 } 134