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
usage(void)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
main(int argc,char * argv[])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