xref: /illumos-gate/usr/src/cmd/cmd-inet/common/addr_match.c (revision e3ae4b35c024af1196582063ecee3ab79367227d)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <netinet/in.h>
31 #include <string.h>
32 #include <syslog.h>
33 #include <addr_match.h>
34 
35 /*
36  * Function to compare IP addresses.  It walks the list provided in
37  * the res parameter, comparing to the original address in sin or sin6,
38  * with some addition guidance provided by fromp.  It returns B_TRUE
39  * if a match is found, otherwise B_FALSE.
40  */
41 
42 static boolean_t
43 find_match(const struct addrinfo *res,
44     const struct sockaddr_storage *fromp,
45     const struct sockaddr_in *sin,
46     const struct sockaddr_in6 *sin6)
47 {
48 	const struct addrinfo *ai;
49 
50 	/* This is the moral equivalent of an assert. */
51 	if ((fromp->ss_family == AF_INET && sin == NULL) ||
52 	    (fromp->ss_family == AF_INET6 && sin6 == NULL))
53 		return (B_FALSE);
54 
55 	for (ai = res; ai != NULL; ai = ai->ai_next) {
56 		struct sockaddr_in *s4;
57 		struct sockaddr_in6 *s6;
58 		void *addr1, *addr2;
59 		size_t size;
60 
61 		if (ai->ai_family != fromp->ss_family)
62 			continue;
63 		if (ai->ai_family == AF_INET) {
64 			/* LINTED E_BAD_PTR_CAST_ALIGN */
65 			s4 = (struct sockaddr_in *)ai->ai_addr;
66 			addr1 = &s4->sin_addr;
67 			addr2 = &((struct sockaddr_in *)sin)->sin_addr;
68 			size = sizeof (struct in_addr);
69 		} else if (ai->ai_family == AF_INET6) {
70 			/* LINTED E_BAD_PTR_CAST_ALIGN */
71 			s6 = (struct sockaddr_in6 *)ai->ai_addr;
72 			addr1 = &s6->sin6_addr;
73 			addr2 = &((struct sockaddr_in6 *)sin6)->sin6_addr;
74 			size = sizeof (struct in6_addr);
75 		} else {
76 			continue;
77 		}
78 		if (memcmp(addr1, addr2, size) == 0)
79 			return (B_TRUE);
80 	}
81 	return (B_FALSE);
82 }
83 
84 void
85 check_address(const char *prog,
86     const struct sockaddr_storage *fromp,
87     const struct sockaddr_in *sin,
88     const struct sockaddr_in6 *sin6,
89     const char *printable_addr,
90     char *hostname,
91     size_t hostsize)
92 {
93 	/*
94 	 * We have to check for spoofing.  So take hostname, look up its
95 	 * address(es), and walk the list until we have a match with the
96 	 * original IP address.  If no match is found, log a warning and
97 	 * use the original IP address for authentication purposes.
98 	 */
99 	struct addrinfo *res, hints;
100 	boolean_t match_found = B_FALSE;
101 
102 	(void) memset(&hints, 0, sizeof (hints));
103 	hints.ai_flags = AI_CANONNAME|AI_V4MAPPED|AI_ADDRCONFIG|AI_ALL;
104 	hints.ai_family = fromp->ss_family;
105 	if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
106 		match_found = find_match(res, fromp, sin, sin6);
107 		freeaddrinfo(res);
108 	}
109 	if (!match_found) {
110 		syslog(LOG_WARNING, "%s: IP address '%s' maps to host "
111 		    "name '%s',\r\n but that host name does not map to "
112 		    "the same IP address.", prog, printable_addr, hostname);
113 		(void) strlcpy(hostname, printable_addr, hostsize);
114 	}
115 }
116