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