1/* $NetBSD: broadcast_bind.c,v 1.2 2022/11/17 08:42:06 ozaki-r Exp $ */
2/* $OpenBSD: broadcast_bind.c,v 1.2 2015/12/02 20:45:00 mpi Exp $ */
3
4/*
5 * Copyright (c) 2015 Vincent Gross <vgross@openbsd.org>
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <err.h>
21#include <errno.h>
22#include <stdio.h>
23#include <unistd.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <arpa/inet.h>
28
29#include <sys/socket.h>
30
31#include <netinet/in.h>
32
33
34static int
35test_bind(char *paddr, struct in_addr *addr, u_int16_t port, int type,
36    int expected_errno)
37{
38	int s, rc;
39	struct sockaddr_in sin;
40
41	memset(&sin, 0, sizeof(sin));
42	sin.sin_family = AF_INET;
43	sin.sin_len = sizeof(sin);
44	sin.sin_port = htons(port);
45	memcpy(&sin.sin_addr, addr, sizeof(*addr));
46
47	s = socket(PF_INET, type, 0);
48	if (s < 0) {
49		warn("socket(PF_INET, %d, 0)", type);
50		return (1);
51	}
52
53	rc = bind(s, (struct sockaddr *)&sin, sin.sin_len);
54	if ((rc == 0 && expected_errno == 0) ||
55	    (rc != 0 && expected_errno == errno)) {
56		close(s);
57		return (0);
58	}
59
60	warn("bind(%s,%d) (type %d) expected %d, got %d", paddr, port, type,
61	    expected_errno, errno);
62	close(s);
63
64	return (1);
65}
66
67int
68main(int argc, char *argv[])
69{
70	int rc;
71	struct in_addr uc_addr, err_addr, bc_addr;
72	int port = 30000;
73
74	if (argc != 4)
75		errx(1, "needs 2 arguments: <unicast> <error> <broadcast>");
76
77	rc = inet_pton(AF_INET, argv[1], &uc_addr);
78	if (rc != 1) {
79		if (rc)
80			err(1, "inet_pton(unicast)");
81		else
82			errx(1, "inet_pton(unicast): error parsing %s",
83			    argv[1]);
84	}
85	rc = inet_pton(AF_INET, argv[2], &err_addr);
86	if (rc != 1) {
87		if (rc)
88			err(1, "inet_pton(error)");
89		else
90			errx(1, "inet_pton(error): error parsing %s", argv[2]);
91	}
92	rc = inet_pton(AF_INET, argv[3], &bc_addr);
93	if (rc != 1) {
94		if (rc)
95			err(1, "inet_pton(broadcast)");
96		else
97			errx(1, "inet_pton(broadcast): error parsing %s",
98			    argv[3]);
99	}
100
101	rc = 0;
102	rc |= test_bind(argv[1], &uc_addr, port, SOCK_STREAM, 0);
103	rc |= test_bind(argv[2], &err_addr, port, SOCK_STREAM, EADDRNOTAVAIL);
104#ifdef __NetBSD__
105	rc |= test_bind(argv[3], &bc_addr, port, SOCK_STREAM, 0);
106#else
107	rc |= test_bind(argv[3], &bc_addr, port, SOCK_STREAM, EADDRNOTAVAIL);
108#endif
109
110	rc |= test_bind(argv[2], &err_addr, port, SOCK_STREAM, EADDRNOTAVAIL);
111	rc |= test_bind(argv[3], &bc_addr, port, SOCK_DGRAM, 0);
112
113	return (rc);
114}
115