]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - tools/regression/netinet/ipbroadcast/ipbroadcast.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / tools / regression / netinet / ipbroadcast / ipbroadcast.c
1 /*-
2  * Copyright (c) 2007 Bruce M. Simpson
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 /*
28  * Test utility for IPv4 broadcast sockets.
29  */
30
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33
34 #include <sys/param.h>
35 #include <sys/types.h>
36 #include <sys/ioctl.h>
37 #include <sys/socket.h>
38
39 #include <net/if.h>
40 #include <net/if_dl.h>
41 #include <netinet/in.h>
42 #include <arpa/inet.h>
43
44 #include <signal.h>
45 #include <stddef.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include <time.h>
50
51 #include <err.h>
52 #include <errno.h>
53 #include <getopt.h>
54 #include <pwd.h>
55 #include <unistd.h>
56 #include <netdb.h>
57 #include <libgen.h>
58
59 #ifndef IP_SENDIF
60 #define IP_SENDIF       24              /* XXX */
61 #endif
62
63 #ifndef IPPROTO_ZEROHOP
64 #define IPPROTO_ZEROHOP 114             /* any 0-hop protocol */
65 #endif
66
67 #define DEFAULT_PORT            6698
68 #define DEFAULT_PAYLOAD_SIZE    24
69 #define DEFAULT_TTL             1
70
71 #define MY_CMSG_SIZE                            \
72         CMSG_SPACE(sizeof(struct in_addr)) +    \
73         CMSG_SPACE(sizeof(struct sockaddr_dl))
74
75 static char *progname = NULL;
76
77 static void
78 usage(void)
79 {
80
81         fprintf(stderr, "IPv4 broadcast test program. Sends a %d byte UDP "
82                 "datagram to <dest>:<port>.\n\n", DEFAULT_PAYLOAD_SIZE);
83         fprintf(stderr,
84 "usage: %s [-1] [-A laddr] [-b] [-B] [-d] [-i iface] [-l len]\n"
85 "                   [-p port] [-R] [-s srcaddr] [-t ttl] <dest>\n",
86             progname);
87         fprintf(stderr, "-1: Set IP_ONESBCAST\n");
88         fprintf(stderr, "-A: specify laddr (default: INADDR_ANY)\n");
89         fprintf(stderr, "-b: bind socket to <laddr>:<lport>\n");
90         fprintf(stderr, "-B: Set SO_BROADCAST\n");
91         fprintf(stderr, "-d: Set SO_DONTROUTE\n");
92         fprintf(stderr, "-i: Set IP_SENDIF <iface> (if supported)\n");
93         fprintf(stderr, "-l: Set payload size to <len>\n");
94         fprintf(stderr, "-p: Set local and remote port (default: %d)\n",
95             DEFAULT_PORT);
96         fprintf(stderr, "-R: Use raw IP (protocol %d)\n", IPPROTO_ZEROHOP);
97 #if 0
98         fprintf(stderr, "-r: Fill datagram with random bytes\n");
99 #endif
100         fprintf(stderr, "-s: Set IP_SENDSRCADDR to <srcaddr>\n");
101         fprintf(stderr, "-t: Set IP_TTL to <ttl>\n");
102
103         exit(EXIT_FAILURE);
104 }
105
106 int
107 main(int argc, char *argv[])
108 {
109         char                    *buf;
110         char                     cmsgbuf[MY_CMSG_SIZE];
111         struct iovec             iov[1];
112         struct msghdr            msg;
113         struct sockaddr_in       dsin;
114         struct sockaddr_in       laddr;
115         struct sockaddr_dl      *sdl;
116         struct cmsghdr          *cmsgp;
117         struct in_addr           dstaddr;
118         struct in_addr          *srcaddrp;
119         char                    *ifname;
120         char                    *laddr_s;
121         char                    *srcaddr_s;
122         int                      ch;
123         int                      dobind;
124         int                      dobroadcast;
125         int                      dontroute;
126         int                      doonesbcast;
127         int                      dorandom;
128         int                      dorawip;
129         size_t                   buflen;
130         ssize_t                  nbytes;
131         int                      portno;
132         int                      ret;
133         int                      s;
134         socklen_t                soptlen;
135         int                      soptval;
136         int                      ttl;
137
138         dobind = 0;
139         dobroadcast = 0;
140         dontroute = 0;
141         doonesbcast = 0;
142         dorandom = 0;
143         dorawip = 0;
144
145         ifname = NULL;
146         dstaddr.s_addr = INADDR_ANY;
147         laddr_s = NULL;
148         srcaddr_s = NULL;
149         portno = DEFAULT_PORT;
150         ttl = DEFAULT_TTL;
151
152         buf = NULL;
153         buflen = DEFAULT_PAYLOAD_SIZE;
154
155         progname = basename(argv[0]);
156         while ((ch = getopt(argc, argv, "1A:bBdi:l:p:Rrs:t:")) != -1) {
157                 switch (ch) {
158                 case '1':
159                         doonesbcast = 1;
160                         break;
161                 case 'A':
162                         laddr_s = optarg;
163                         break;
164                 case 'b':
165                         dobind = 1;
166                         break;
167                 case 'B':
168                         dobroadcast = 1;
169                         break;
170                 case 'd':
171                         dontroute = 1;
172                         break;
173                 case 'i':
174                         ifname = optarg;
175                         break;
176                 case 'l':
177                         buflen = atoi(optarg);
178                         break;
179                 case 'p':
180                         portno = atoi(optarg);
181                         break;
182                 case 'R':
183                         dorawip = 1;
184                         break;
185                 case 'r':
186                         dorandom = 1;
187                         break;
188                 case 's':
189                         srcaddr_s = optarg;
190                         break;
191                 case 't':
192                         ttl = atoi(optarg);
193                         break;
194                 default:
195                         usage();
196                         break;
197                 }
198         }
199         argc -= optind;
200         argv += optind;
201
202         if (argc != 1)
203                 usage();
204         if (argv[0] == NULL || inet_aton(argv[0], &dstaddr) == 0)
205                 usage();
206         /* IP_SENDSRCADDR and IP_SENDIF are mutually exclusive just now. */
207         if (srcaddr_s != NULL && ifname != NULL)
208                 usage();
209         if (dorawip) {
210                 if (geteuid() != 0)
211                         fprintf(stderr, "WARNING: not running as root.\n");
212                 s = socket(PF_INET, SOCK_RAW, IPPROTO_ZEROHOP);
213         } else {
214                 s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
215         }
216         if (s == -1) {
217                 perror("socket");
218                 exit(EXIT_FAILURE);
219         }
220
221         if (dontroute) {
222                 soptval = 1;
223                 soptlen = sizeof(soptval);
224                 ret = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &soptval,
225                     soptlen);
226                 if (ret == -1) {
227                         perror("setsockopt SO_DONTROUTE");
228                         close(s);
229                         exit(EXIT_FAILURE);
230                 }
231         }
232
233         if (dobroadcast) {
234                 soptval = 1;
235                 soptlen = sizeof(soptval);
236                 ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &soptval,
237                     soptlen);
238                 if (ret == -1) {
239                         perror("setsockopt SO_BROADCAST");
240                         close(s);
241                         exit(EXIT_FAILURE);
242                 }
243         }
244
245         soptval = ttl;
246         soptlen = sizeof(soptval);
247         ret = setsockopt(s, IPPROTO_IP, IP_TTL, &soptval, soptlen);
248         if (ret == -1) {
249                 perror("setsockopt IPPROTO_IP IP_TTL");
250                 close(s);
251                 exit(EXIT_FAILURE);
252         }
253
254         if (doonesbcast) {
255                 soptval = 1;
256                 soptlen = sizeof(soptval);
257                 ret = setsockopt(s, IPPROTO_IP, IP_ONESBCAST, &soptval,
258                     soptlen);
259                 if (ret == -1) {
260                         perror("setsockopt IP_ONESBCAST");
261                         close(s);
262                         exit(EXIT_FAILURE);
263                 }
264         }
265
266         if (dobind) {
267                 memset(&laddr, 0, sizeof(struct sockaddr_in));
268                 laddr.sin_family = AF_INET;
269                 laddr.sin_len = sizeof(struct sockaddr_in);
270                 if (laddr_s != NULL) {
271                         laddr.sin_addr.s_addr = inet_addr(laddr_s);
272                 } else
273                         laddr.sin_addr.s_addr = INADDR_ANY;
274                 laddr.sin_port = htons(portno);
275                 ret = bind(s, (struct sockaddr *)&laddr, sizeof(laddr));
276                 if (ret == -1) {
277                         perror("bind");
278                         close(s);
279                         exit(EXIT_FAILURE);
280                 }
281         }
282
283         memset(&dsin, 0, sizeof(struct sockaddr_in));
284         dsin.sin_family = AF_INET;
285         dsin.sin_len = sizeof(struct sockaddr_in);
286         dsin.sin_addr.s_addr = dstaddr.s_addr;
287         dsin.sin_port = htons(portno);
288
289         buf = malloc(buflen);
290         if (buf == NULL) {
291                 perror("malloc");
292                 close(s);
293                 exit(EXIT_FAILURE);
294         }
295         memset(iov, 0, sizeof(iov));
296         iov[0].iov_base = buf;
297         iov[0].iov_len = buflen;
298
299         memset(&msg, 0, sizeof(struct msghdr));
300         msg.msg_name = &dsin;
301         msg.msg_namelen = sizeof(dsin);
302         msg.msg_iov = iov;
303         msg.msg_iovlen = 1;
304
305         /* Assume we fill out a control msg; macros need to see buf ptr */
306         msg.msg_control = cmsgbuf;
307         msg.msg_controllen = 0;
308         memset(cmsgbuf, 0, MY_CMSG_SIZE);
309
310         /* IP_SENDSRCADDR and IP_SENDIF are mutually exclusive just now. */
311         if (srcaddr_s != NULL) {
312                 msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));
313                 cmsgp = CMSG_FIRSTHDR(&msg);
314                 cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
315                 cmsgp->cmsg_level = IPPROTO_IP;
316                 cmsgp->cmsg_type = IP_SENDSRCADDR;
317                 srcaddrp = (struct in_addr *)CMSG_DATA(cmsgp);
318                 srcaddrp->s_addr = inet_addr(srcaddr_s);
319         }
320
321         if (ifname != NULL) {
322 #ifdef IP_SENDIF
323                 msg.msg_controllen += CMSG_SPACE(sizeof(struct sockaddr_dl));
324                 cmsgp = CMSG_FIRSTHDR(&msg);
325                 cmsgp->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_dl));
326                 cmsgp->cmsg_level = IPPROTO_IP;
327                 cmsgp->cmsg_type = IP_SENDIF;
328
329 #ifdef DIAGNOSTIC
330                 fprintf(stderr, "DEBUG: cmsgp->cmsg_len is %d\n",
331                     cmsgp->cmsg_len);
332 #endif
333
334                 sdl = (struct sockaddr_dl *)CMSG_DATA(cmsgp);
335                 memset(sdl, 0, sizeof(struct sockaddr_dl));
336                 sdl->sdl_family = AF_LINK;
337                 sdl->sdl_len = sizeof(struct sockaddr_dl);
338                 sdl->sdl_index = if_nametoindex(ifname);
339
340 #ifdef DIAGNOSTIC
341                 fprintf(stderr, "DEBUG: sdl->sdl_family is %d\n",
342                     sdl->sdl_family);
343                 fprintf(stderr, "DEBUG: sdl->sdl_len is %d\n",
344                     sdl->sdl_len);
345                 fprintf(stderr, "DEBUG: sdl->sdl_index is %d\n",
346                     sdl->sdl_index);
347 #endif
348 #else
349                 fprintf(stderr, "WARNING: IP_SENDIF not supported, ignored.\n");
350 #endif
351         }
352
353         if (msg.msg_controllen == 0)
354                 msg.msg_control = NULL;
355
356         nbytes = sendmsg(s, &msg, (dontroute ? MSG_DONTROUTE : 0));
357         if (nbytes == -1) {
358                 perror("sendmsg");
359                 close(s);
360                 exit(EXIT_FAILURE);
361         }
362
363         close(s);
364
365         exit(EXIT_SUCCESS);
366 }