xref: /openbsd/regress/sys/netinet6/mcast6/mc6send.c (revision 3cab2bb3)
1 /*	$OpenBSD: mc6send.c,v 1.1.1.1 2019/09/05 01:50:34 bluhm Exp $	*/
2 /*
3  * Copyright (c) 2019 Alexander Bluhm <bluhm@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/socket.h>
19 
20 #include <arpa/inet.h>
21 #include <net/if.h>
22 #include <netinet/in.h>
23 
24 #include <err.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 void __dead usage(void);
31 
32 void __dead
33 usage(void)
34 {
35 	fprintf(stderr,
36 "mc6send [-f file] [-g group] [-i ifname] [-m message] [-p port]\n"
37 "    -f file         print message to log file, default stdout\n"
38 "    -g group        multicast group, default 224.0.0.123\n"
39 "    -i ifname       multicast interface address\n"
40 "    -m message      message in payload, maximum 255 characters, default foo\n"
41 "    -l loop         disable or enable loopback, 0 or 1\n"
42 "    -p port         destination port number, default 12345\n"
43 "    -t ttl          set multicast ttl\n");
44 	exit(2);
45 }
46 
47 int
48 main(int argc, char *argv[])
49 {
50 	struct sockaddr_in6 sin6;
51 	FILE *log;
52 	const char *errstr, *file, *group, *ifname, *msg;
53 	size_t len;
54 	ssize_t n;
55 	int ch, s, loop, port, ttl;
56 	unsigned int ifindex;
57 
58 	log = stdout;
59 	file = NULL;
60 	group = "ff04::123";
61 	ifname = NULL;
62 	loop = -1;
63 	msg = "foo";
64 	port = 12345;
65 	ttl = -1;
66 	while ((ch = getopt(argc, argv, "f:g:i:l:m:p:t:")) != -1) {
67 		switch (ch) {
68 		case 'f':
69 			file = optarg;
70 			break;
71 		case 'g':
72 			group = optarg;
73 			break;
74 		case 'i':
75 			ifname = optarg;
76 			break;
77 		case 'l':
78 			loop = strtonum(optarg, 0, 1, &errstr);
79 			if (errstr != NULL)
80 				errx(1, "loop is %s: %s", errstr, optarg);
81 			break;
82 		case 'm':
83 			msg = optarg;
84 			break;
85 		case 'p':
86 			port = strtonum(optarg, 1, 0xffff, &errstr);
87 			if (errstr != NULL)
88 				errx(1, "port is %s: %s", errstr, optarg);
89 			break;
90 		case 't':
91 			ttl = strtonum(optarg, 0, 255, &errstr);
92 			if (errstr != NULL)
93 				errx(1, "ttl is %s: %s", errstr, optarg);
94 			break;
95 		default:
96 			usage();
97 		}
98 	}
99 	argc -= optind;
100 	argv += optind;
101 	if (argc)
102 		usage();
103 
104 	if (file != NULL) {
105 		log = fopen(file, "w");
106 		if (log == NULL)
107 			err(1, "fopen %s", file);
108 	}
109 
110 	s = socket(AF_INET6, SOCK_DGRAM, 0);
111 	if (s == -1)
112 		err(1, "socket");
113 	if (ifname != NULL) {
114 		ifindex = if_nametoindex(ifname);
115 		if (ifindex == 0)
116 			err(1, "if_nametoindex %s", ifname);
117 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_IF, &ifindex,
118 		    sizeof(ifindex)) == -1)
119 			err(1, "setsockopt IPV6_MULTICAST_IF %s", ifname);
120 	}
121 	if (loop != -1) {
122 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &loop,
123 		    sizeof(loop)) == -1)
124 			err(1, "setsockopt loop %d", loop);
125 	}
126 	if (ttl != -1) {
127 		if (setsockopt(s, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl,
128 		    sizeof(ttl)) == -1)
129 			err(1, "setsockopt ttl %d", ttl);
130 	}
131 
132 	memset(&sin6, 0, sizeof(sin6));
133 	sin6.sin6_len = sizeof(sin6);
134 	sin6.sin6_family = AF_INET6;
135 	sin6.sin6_port = htons(port);
136 	if (inet_pton(AF_INET6, group, &sin6.sin6_addr) == -1)
137 		err(1, "inet_pton %s", group);
138 	if (ifname != NULL &&
139 	    (IN6_IS_ADDR_LINKLOCAL(&sin6.sin6_addr) ||
140 	    IN6_IS_ADDR_MC_LINKLOCAL(&sin6.sin6_addr) ||
141 	    IN6_IS_ADDR_MC_INTFACELOCAL(&sin6.sin6_addr))) {
142 		sin6.sin6_scope_id = ifindex;
143 	}
144 	if (connect(s, (struct sockaddr *)&sin6, sizeof(sin6)) == -1)
145 		err(1, "connect [%s]:%d", group, port);
146 
147 	len = strlen(msg);
148 	if (len >= 255)
149 		err(1, "message too long %zu", len);
150 	n = send(s, msg, len, 0);
151 	if (n == -1)
152 		err(1, "send");
153 	if ((size_t)n != len)
154 		errx(1, "send %zd", n);
155 	fprintf(log, ">>> %s\n", msg);
156 	fflush(log);
157 
158 	return 0;
159 }
160