1 /* $OpenBSD: mcsend.c,v 1.2 2019/09/05 02:44:36 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 <netinet/in.h>
22
23 #include <err.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28
29 void __dead usage(void);
30
31 void __dead
usage(void)32 usage(void)
33 {
34 fprintf(stderr,
35 "mcsend [-f file] [-g group] [-i ifaddr] [-m message] [-p port]\n"
36 " -f file print message to log file, default stdout\n"
37 " -g group multicast group, default 224.0.0.123\n"
38 " -i ifaddr multicast interface address\n"
39 " -m message message in payload, maximum 255 characters, default foo\n"
40 " -l loop disable or enable loopback, 0 or 1\n"
41 " -p port destination port number, default 12345\n"
42 " -t ttl set multicast ttl\n");
43 exit(2);
44 }
45
46 int
main(int argc,char * argv[])47 main(int argc, char *argv[])
48 {
49 struct sockaddr_in sin;
50 FILE *log;
51 const char *errstr, *file, *group, *ifaddr, *msg;
52 size_t len;
53 ssize_t n;
54 int ch, s, loop, port, ttl;
55
56 log = stdout;
57 file = NULL;
58 group = "224.0.1.123";
59 ifaddr = NULL;
60 loop = -1;
61 msg = "foo";
62 port = 12345;
63 ttl = -1;
64 while ((ch = getopt(argc, argv, "f:g:i:l:m:p:t:")) != -1) {
65 switch (ch) {
66 case 'f':
67 file = optarg;
68 break;
69 case 'g':
70 group = optarg;
71 break;
72 case 'i':
73 ifaddr = optarg;
74 break;
75 case 'l':
76 loop = strtonum(optarg, 0, 1, &errstr);
77 if (errstr != NULL)
78 errx(1, "loop is %s: %s", errstr, optarg);
79 break;
80 case 'm':
81 msg = optarg;
82 break;
83 case 'p':
84 port = strtonum(optarg, 1, 0xffff, &errstr);
85 if (errstr != NULL)
86 errx(1, "port is %s: %s", errstr, optarg);
87 break;
88 case 't':
89 ttl = strtonum(optarg, 0, 255, &errstr);
90 if (errstr != NULL)
91 errx(1, "ttl is %s: %s", errstr, optarg);
92 break;
93 default:
94 usage();
95 }
96 }
97 argc -= optind;
98 argv += optind;
99 if (argc)
100 usage();
101
102 if (file != NULL) {
103 log = fopen(file, "w");
104 if (log == NULL)
105 err(1, "fopen %s", file);
106 }
107
108 s = socket(AF_INET, SOCK_DGRAM, 0);
109 if (s == -1)
110 err(1, "socket");
111 if (ifaddr != NULL) {
112 struct in_addr addr;
113
114 if (inet_pton(AF_INET, ifaddr, &addr) == -1)
115 err(1, "inet_pton %s", ifaddr);
116 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF, &addr,
117 sizeof(addr)) == -1)
118 err(1, "setsockopt IP_MULTICAST_IF %s", ifaddr);
119 }
120 if (loop != -1) {
121 unsigned char value = loop;
122
123 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_LOOP, &value,
124 sizeof(value)) == -1)
125 err(1, "setsockopt loop %d", loop);
126 }
127 if (ttl != -1) {
128 unsigned char value = ttl;
129
130 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &value,
131 sizeof(value)) == -1)
132 err(1, "setsockopt ttl %d", ttl);
133 }
134
135 memset(&sin, 0, sizeof(sin));
136 sin.sin_len = sizeof(sin);
137 sin.sin_family = AF_INET;
138 sin.sin_port = htons(port);
139 if (inet_pton(AF_INET, group, &sin.sin_addr) == -1)
140 err(1, "inet_pton %s", group);
141 if (connect(s, (struct sockaddr *)&sin, sizeof(sin)) == -1)
142 err(1, "connect %s:%d", group, port);
143
144 len = strlen(msg);
145 if (len >= 255)
146 err(1, "message too long %zu", len);
147 n = send(s, msg, len, 0);
148 if (n == -1)
149 err(1, "send");
150 if ((size_t)n != len)
151 errx(1, "send %zd", n);
152 fprintf(log, ">>> %s\n", msg);
153 fflush(log);
154
155 return 0;
156 }
157