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