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 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 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