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