2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
13 * Copyright 2016 Nexenta Systems, Inc.
19 * Match IPv4 or IPv6 address provided in sa (sockaddr_in/sockaddr_in6)
20 * against standard text representation specified in name:
34 * -1 error occured, caller should check errno:
35 * EINVAL access list entry is invalid
36 * ENOMEM failed to allocate memory
39 #include <sys/socket.h>
40 #include <sys/types.h>
42 #include <arpa/inet.h>
44 #include <netinet/in.h>
53 inet_matchaddr(const void *sa
, const char *name
)
61 if ((p
= lname
= strdup(name
)) == NULL
) {
66 if ((mp
= strchr(p
, '/')) != NULL
)
69 switch (((struct sockaddr_in
*)sa
)->sin_family
) {
73 struct in6_addr hcaddr6
;
74 struct in6_addr
*claddr6
=
75 &((struct sockaddr_in6
*)sa
)->sin6_addr
;
77 if (!IN6_IS_ADDR_V4MAPPED(claddr6
)) {
85 if ((pp
= strchr(p
, ']')) == NULL
||
86 (mp
!= NULL
&& pp
!= mp
- 2) ||
87 (mp
== NULL
&& *(pp
+ 1) != '\0')) {
93 if (inet_pton(AF_INET6
, p
, &hcaddr6
) != 1) {
99 /* Match only first prefix bits */
103 prefix6
= strtol(mp
, &ep
, 10);
104 if (errno
!= 0 || prefix6
< 0 ||
105 prefix6
> 128 || *ep
!= '\0') {
109 ret
= IN6_ARE_PREFIXEDADDR_EQUAL(claddr6
,
110 &hcaddr6
, prefix6
) ? 1 : 0;
113 /* No prefix, exact match */
114 ret
= IN6_ARE_ADDR_EQUAL(claddr6
,
119 /* IPv4-mapped IPv6 address, fallthrough to IPv4 */
120 IN6_V4MAPPED_TO_IPADDR(claddr6
, ipaddr4
);
121 claddr4
= ntohl(ipaddr4
);
127 uint32_t hcaddr4
= 0, mask4
;
131 ((struct sockaddr_in
*)sa
)->sin_addr
.s_addr
);
134 for (i
= 0; i
< 4; i
++) {
138 qaddr4
= strtol(p
, &ep
, 10);
139 if (errno
!= 0 || qaddr4
< 0 || qaddr4
> 255 ||
140 (*ep
!= '.' && *ep
!= '\0')) {
144 hcaddr4
|= qaddr4
<< ((3 - i
) * 8);
154 /* Mask is specified explicitly */
158 mb
= strtol(mp
, &ep
, 10);
159 if (errno
!= 0 || mb
< 0 || mb
> 32 || *ep
!= '\0') {
163 mask4
= mb
? ~0 << ((sizeof (struct in_addr
) * NBBY
)
168 * Use old-fashioned implicit netmasking by checking
169 * for lower-end zeroes. On the off chance we don't
170 * match any well-known prefixes, return an exact-
171 * match prefix which is misleadingly labelled as
174 if ((hcaddr4
& IN_CLASSA_HOST
) == 0)
175 mask4
= IN_CLASSA_NET
;
176 else if ((hcaddr4
& IN_CLASSB_HOST
) == 0)
177 mask4
= IN_CLASSB_NET
;
178 else if ((hcaddr4
& IN_CLASSC_HOST
) == 0)
179 mask4
= IN_CLASSC_NET
;
181 mask4
= IN_CLASSE_NET
;
184 ret
= ((claddr4
& mask4
) == hcaddr4
) ? 1 : 0;