1/* $NetBSD: netmask.c,v 1.2 2009/06/30 02:44:52 agc Exp $ */
2
3/*
4 * Copyright � 2006 Alistair Crooks.  All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote
15 *    products derived from this software without specific prior written
16 *    permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
19 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
24 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
26 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30#include "config.h"
31
32#include <sys/types.h>
33#include <sys/param.h>
34
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39
40#ifdef HAVE_NETINET_IN_H
41#include <netinet/in.h>
42#endif
43
44#ifdef HAVE_ARPA_INET_H
45#include <arpa/inet.h>
46#endif
47
48#include "iscsiutil.h"
49
50enum {
51	NETMASK_BUFFER_SIZE = 256
52};
53
54/* this struct is used to define a magic netmask value */
55typedef struct magic_t {
56	const char	*magic;	/* string to match */
57	const char	*xform;	/* string to transform it into */
58} magic_t;
59
60
61static magic_t	magics[] = {
62	{	"any",	"0/0"	},
63	{	"all",	"0/0"	},
64	{	"none",	"0/32"	},
65	{	NULL,	NULL	},
66};
67
68#ifndef ISCSI_HTONL
69#define ISCSI_HTONL(x)	htonl(x)
70#endif
71
72/* return 1 if address is in netmask's range */
73int
74allow_netmask(const char *netmaskarg, const char *addr)
75{
76	struct in_addr	 a;
77	struct in_addr	 m;
78	const char	*netmask;
79	magic_t		*mp;
80	char	 	 maskaddr[NETMASK_BUFFER_SIZE];
81	char		*cp;
82	int		 slash;
83	int		 i;
84
85	/* firstly check for any magic values in the netmask */
86	netmask = netmaskarg;
87	for (mp = magics ; mp->magic ; mp++) {
88		if (strcmp(netmask, mp->magic) == 0) {
89			netmask = mp->xform;
90			break;
91		}
92	}
93
94	/* find out if slash notation has been used */
95	(void) memset(&a, 0x0, sizeof(a));
96	if ((cp = strchr(netmask, '/')) == NULL) {
97		(void) strlcpy(maskaddr, netmask, sizeof(maskaddr));
98		slash = 32;
99	} else {
100		(void) strlcpy(maskaddr, netmask, MIN(sizeof(maskaddr), (size_t)(cp - netmask) + 1));
101		slash = atoi(cp + 1);
102	}
103
104	/* if we have a wildcard "slash" netmask, then we allow it */
105	if (slash == 0) {
106		return 1;
107	}
108
109	/* canonicalise IPv4 address to dotted quad */
110	for (i = 0, cp = maskaddr ; *cp ; cp++) {
111		if (*cp == '.') {
112			i += 1;
113		}
114	}
115	for ( ; i < 3 ; i++) {
116		(void) snprintf(cp, sizeof(maskaddr) - (int)(cp - maskaddr), ".0");
117		cp += 2;
118	}
119
120	/* translate netmask to in_addr */
121	if (!inet_aton(maskaddr, &m)) {
122		(void) fprintf(stderr, "allow_netmask: can't interpret mask `%s' as an IPv4 address\n", maskaddr);
123		return 0;
124	}
125
126	/* translate address to in_addr */
127	if (!inet_aton(addr, &a)) {
128		(void) fprintf(stderr, "allow_netmask: can't interpret address `%s' as an IPv4 address\n", addr);
129		return 0;
130	}
131
132#ifdef ALLOW_NETMASK_DEBUG
133	printf("addr %s %08x, mask %s %08x, slash %d\n", addr, (ISCSI_HTONL(a.s_addr) >> (32 - slash)), maskaddr, (ISCSI_HTONL(m.s_addr) >> (32 - slash)), slash);
134#endif
135
136	/* and return 1 if address is in netmask */
137	return (ISCSI_HTONL(a.s_addr) >> (32 - slash)) == (ISCSI_HTONL(m.s_addr) >> (32 - slash));
138}
139
140#ifdef ALLOW_NETMASK_DEBUG
141int
142main(int argc, char **argv)
143{
144	int	i;
145
146	for (i = 1 ; i < argc ; i+= 2) {
147		if (allow_netmask(argv[i], argv[i + 1])) {
148			printf("mask %s matches addr %s\n\n", argv[i], argv[i + 1]);
149		} else {
150			printf("No match for mask %s from addr %s\n\n", argv[i], argv[i + 1]);
151		}
152	}
153	exit(EXIT_SUCCESS);
154}
155#endif
156
157#if 0
158[11:33:02] agc@sys3 ...local/src/netmask 248 > ./n 10.4/16 10.4.0.29 10.4/16 10.5.0.29 10.4/0 10.4.0.19 10.4 10.4.0.19 10.4.3/8 10.4.3.7 10.4.3/24 10.4.3.7
159mask 10.4/16 matches addr 10.4.0.29
160
161No match for mask 10.4/16 from addr 10.5.0.29
162
163mask 10.4/0 matches addr 10.4.0.19
164
165No match for mask 10.4 from addr 10.4.0.19
166
167mask 10.4.3/8 matches addr 10.4.3.7
168
169mask 10.4.3/24 matches addr 10.4.3.7
170
171[14:44:52] agc@sys3 ...local/src/netmask 249 >
172#endif
173