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