Path: blob/main/tools/regression/netinet/ipbroadcast/ipbroadcast.c
39536 views
/*-1* Copyright (c) 2007 Bruce M. Simpson2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526/*27* Test utility for IPv4 broadcast sockets.28*/2930#include <sys/param.h>31#include <sys/types.h>32#include <sys/ioctl.h>33#include <sys/socket.h>3435#include <net/if.h>36#include <net/if_dl.h>37#include <netinet/in.h>38#include <arpa/inet.h>3940#include <signal.h>41#include <stddef.h>42#include <stdio.h>43#include <stdlib.h>44#include <string.h>45#include <time.h>4647#include <err.h>48#include <errno.h>49#include <getopt.h>50#include <pwd.h>51#include <unistd.h>52#include <netdb.h>53#include <libgen.h>5455#ifndef IP_SENDIF56#define IP_SENDIF 24 /* XXX */57#endif5859#ifndef IPPROTO_ZEROHOP60#define IPPROTO_ZEROHOP 114 /* any 0-hop protocol */61#endif6263#define DEFAULT_PORT 669864#define DEFAULT_PAYLOAD_SIZE 2465#define DEFAULT_TTL 16667#define MY_CMSG_SIZE \68CMSG_SPACE(sizeof(struct in_addr)) + \69CMSG_SPACE(sizeof(struct sockaddr_dl))7071static char *progname = NULL;7273static void74usage(void)75{7677fprintf(stderr, "IPv4 broadcast test program. Sends a %d byte UDP "78"datagram to <dest>:<port>.\n\n", DEFAULT_PAYLOAD_SIZE);79fprintf(stderr,80"usage: %s [-1] [-A laddr] [-b] [-B] [-d] [-i iface] [-l len]\n"81" [-p port] [-R] [-s srcaddr] [-t ttl] <dest>\n",82progname);83fprintf(stderr, "-1: Set IP_ONESBCAST\n");84fprintf(stderr, "-A: specify laddr (default: INADDR_ANY)\n");85fprintf(stderr, "-b: bind socket to <laddr>:<lport>\n");86fprintf(stderr, "-B: Set SO_BROADCAST\n");87fprintf(stderr, "-d: Set SO_DONTROUTE\n");88fprintf(stderr, "-i: Set IP_SENDIF <iface> (if supported)\n");89fprintf(stderr, "-l: Set payload size to <len>\n");90fprintf(stderr, "-p: Set local and remote port (default: %d)\n",91DEFAULT_PORT);92fprintf(stderr, "-R: Use raw IP (protocol %d)\n", IPPROTO_ZEROHOP);93fprintf(stderr, "-s: Set IP_SENDSRCADDR to <srcaddr>\n");94fprintf(stderr, "-t: Set IP_TTL to <ttl>\n");9596exit(EXIT_FAILURE);97}9899int100main(int argc, char *argv[])101{102char *buf;103char cmsgbuf[MY_CMSG_SIZE];104struct iovec iov[1];105struct msghdr msg;106struct sockaddr_in dsin;107struct sockaddr_in laddr;108struct cmsghdr *cmsgp;109struct in_addr dstaddr;110char *ifname;111char *laddr_s;112char *srcaddr_s;113int ch;114int dobind;115int dobroadcast;116int dontroute;117int doonesbcast;118int dorawip;119size_t buflen;120ssize_t nbytes;121int portno;122int ret;123int s;124socklen_t soptlen;125int soptval;126int ttl;127128dobind = 0;129dobroadcast = 0;130dontroute = 0;131doonesbcast = 0;132dorawip = 0;133134ifname = NULL;135dstaddr.s_addr = INADDR_ANY;136laddr_s = NULL;137srcaddr_s = NULL;138portno = DEFAULT_PORT;139ttl = DEFAULT_TTL;140141buf = NULL;142buflen = DEFAULT_PAYLOAD_SIZE;143144progname = basename(argv[0]);145while ((ch = getopt(argc, argv, "1A:bBdi:l:p:Rs:t:")) != -1) {146switch (ch) {147case '1':148doonesbcast = 1;149break;150case 'A':151laddr_s = optarg;152break;153case 'b':154dobind = 1;155break;156case 'B':157dobroadcast = 1;158break;159case 'd':160dontroute = 1;161break;162case 'i':163ifname = optarg;164break;165case 'l':166buflen = atoi(optarg);167break;168case 'p':169portno = atoi(optarg);170break;171case 'R':172dorawip = 1;173break;174case 's':175srcaddr_s = optarg;176break;177case 't':178ttl = atoi(optarg);179break;180default:181usage();182break;183}184}185argc -= optind;186argv += optind;187188if (argc != 1)189usage();190if (argv[0] == NULL || inet_aton(argv[0], &dstaddr) == 0)191usage();192/* IP_SENDSRCADDR and IP_SENDIF are mutually exclusive just now. */193if (srcaddr_s != NULL && ifname != NULL)194usage();195if (dorawip) {196if (geteuid() != 0)197fprintf(stderr, "WARNING: not running as root.\n");198s = socket(PF_INET, SOCK_RAW, IPPROTO_ZEROHOP);199} else {200s = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);201}202if (s == -1) {203perror("socket");204exit(EXIT_FAILURE);205}206207if (dontroute) {208soptval = 1;209soptlen = sizeof(soptval);210ret = setsockopt(s, SOL_SOCKET, SO_DONTROUTE, &soptval,211soptlen);212if (ret == -1) {213perror("setsockopt SO_DONTROUTE");214close(s);215exit(EXIT_FAILURE);216}217}218219if (dobroadcast) {220soptval = 1;221soptlen = sizeof(soptval);222ret = setsockopt(s, SOL_SOCKET, SO_BROADCAST, &soptval,223soptlen);224if (ret == -1) {225perror("setsockopt SO_BROADCAST");226close(s);227exit(EXIT_FAILURE);228}229}230231soptval = ttl;232soptlen = sizeof(soptval);233ret = setsockopt(s, IPPROTO_IP, IP_TTL, &soptval, soptlen);234if (ret == -1) {235perror("setsockopt IPPROTO_IP IP_TTL");236close(s);237exit(EXIT_FAILURE);238}239240if (doonesbcast) {241soptval = 1;242soptlen = sizeof(soptval);243ret = setsockopt(s, IPPROTO_IP, IP_ONESBCAST, &soptval,244soptlen);245if (ret == -1) {246perror("setsockopt IP_ONESBCAST");247close(s);248exit(EXIT_FAILURE);249}250}251252if (dobind) {253memset(&laddr, 0, sizeof(struct sockaddr_in));254laddr.sin_family = AF_INET;255laddr.sin_len = sizeof(struct sockaddr_in);256if (laddr_s != NULL) {257laddr.sin_addr.s_addr = inet_addr(laddr_s);258} else259laddr.sin_addr.s_addr = INADDR_ANY;260laddr.sin_port = htons(portno);261ret = bind(s, (struct sockaddr *)&laddr, sizeof(laddr));262if (ret == -1) {263perror("bind");264close(s);265exit(EXIT_FAILURE);266}267}268269memset(&dsin, 0, sizeof(struct sockaddr_in));270dsin.sin_family = AF_INET;271dsin.sin_len = sizeof(struct sockaddr_in);272dsin.sin_addr.s_addr = dstaddr.s_addr;273dsin.sin_port = htons(portno);274275buf = malloc(buflen);276if (buf == NULL) {277perror("malloc");278close(s);279exit(EXIT_FAILURE);280}281memset(iov, 0, sizeof(iov));282iov[0].iov_base = buf;283iov[0].iov_len = buflen;284285memset(&msg, 0, sizeof(struct msghdr));286msg.msg_name = &dsin;287msg.msg_namelen = sizeof(dsin);288msg.msg_iov = iov;289msg.msg_iovlen = 1;290291/* Assume we fill out a control msg; macros need to see buf ptr */292msg.msg_control = cmsgbuf;293msg.msg_controllen = 0;294memset(cmsgbuf, 0, MY_CMSG_SIZE);295296/* IP_SENDSRCADDR and IP_SENDIF are mutually exclusive just now. */297if (srcaddr_s != NULL) {298msg.msg_controllen += CMSG_SPACE(sizeof(struct in_addr));299cmsgp = CMSG_FIRSTHDR(&msg);300cmsgp->cmsg_len = CMSG_LEN(sizeof(struct in_addr));301cmsgp->cmsg_level = IPPROTO_IP;302cmsgp->cmsg_type = IP_SENDSRCADDR;303memcpy(CMSG_DATA(cmsgp),304&(struct in_addr){ inet_addr(srcaddr_s) },305sizeof(struct in_addr));306}307308if (ifname != NULL) {309#ifdef IP_SENDIF310msg.msg_controllen += CMSG_SPACE(sizeof(struct sockaddr_dl));311cmsgp = CMSG_FIRSTHDR(&msg);312cmsgp->cmsg_len = CMSG_LEN(sizeof(struct sockaddr_dl));313cmsgp->cmsg_level = IPPROTO_IP;314cmsgp->cmsg_type = IP_SENDIF;315316#ifdef DIAGNOSTIC317fprintf(stderr, "DEBUG: cmsgp->cmsg_len is %d\n",318cmsgp->cmsg_len);319#endif320memcpy(CMSG_DATA(cmsgp), &(struct sockaddr_dl){321.sdl_family = AF_LINK,322.sdl_len = sizeof(struct sockaddr_dl),323.sdl_index = if_nametoindex(ifname) },324sizeof(struct sockaddr_dl));325#ifdef DIAGNOSTIC326fprintf(stderr, "DEBUG: sdl->sdl_family is %d\n",327sdl->sdl_family);328fprintf(stderr, "DEBUG: sdl->sdl_len is %d\n",329sdl->sdl_len);330fprintf(stderr, "DEBUG: sdl->sdl_index is %d\n",331sdl->sdl_index);332#endif333#else334fprintf(stderr, "WARNING: IP_SENDIF not supported, ignored.\n");335#endif336}337338if (msg.msg_controllen == 0)339msg.msg_control = NULL;340341nbytes = sendmsg(s, &msg, (dontroute ? MSG_DONTROUTE : 0));342if (nbytes == -1) {343perror("sendmsg");344close(s);345exit(EXIT_FAILURE);346}347348close(s);349350exit(EXIT_SUCCESS);351}352353354