Renamed sum_table -> hash_table.
[rsync/rsync.git] / clientname.c
CommitLineData
0cd2f407 1/* -*- c-file-style: "linux" -*-
c1e7217f 2
0cd2f407 3 rsync -- fast file replication program
c1e7217f 4
0cd2f407
MP
5 Copyright (C) 1992-2001 by Andrew Tridgell <tridge@samba.org>
6 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org>
c1e7217f 7
0cd2f407
MP
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
c1e7217f 12
0cd2f407
MP
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
c1e7217f 17
0cd2f407
MP
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21*/
22
23/**
24 * @file clientname.c
c1e7217f 25 *
0cd2f407
MP
26 * Functions for looking up the remote name or addr of a socket.
27 *
28 * This file is now converted to use the new-style getaddrinfo()
29 * interface, which supports IPv6 but is also supported on recent
30 * IPv4-only machines. On systems that don't have that interface, we
31 * emulate it using the KAME implementation.
32 **/
33
34#include "rsync.h"
35
36static const char default_name[] = "UNKNOWN";
542ad675 37extern int am_server;
0cd2f407
MP
38
39
40/**
c1e7217f 41 * Return the IP addr of the client as a string
0cd2f407
MP
42 **/
43char *client_addr(int fd)
44{
0cd2f407
MP
45 static char addr_buf[100];
46 static int initialised;
b2ef4f61
WD
47 struct sockaddr_storage ss;
48 socklen_t length = sizeof ss;
49 char *ssh_info, *p;
0cd2f407 50
4cfa6156
WD
51 if (initialised)
52 return addr_buf;
0cd2f407
MP
53
54 initialised = 1;
55
706c7530 56 if (am_server) { /* daemon over --rsh mode */
542ad675 57 strcpy(addr_buf, "0.0.0.0");
b2ef4f61
WD
58 if ((ssh_info = getenv("SSH_CONNECTION")) != NULL
59 || (ssh_info = getenv("SSH_CLIENT")) != NULL
60 || (ssh_info = getenv("SSH2_CLIENT")) != NULL) {
61 strlcpy(addr_buf, ssh_info, sizeof addr_buf);
62 /* Truncate the value to just the IP address. */
63 if ((p = strchr(addr_buf, ' ')) != NULL)
64 *p = '\0';
542ad675 65 }
3b5f6214 66 } else {
09021eab 67 client_sockaddr(fd, &ss, &length);
3b5f6214
WD
68 getnameinfo((struct sockaddr *)&ss, length,
69 addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
70 }
09021eab 71
0cd2f407
MP
72 return addr_buf;
73}
74
75
76static int get_sockaddr_family(const struct sockaddr_storage *ss)
77{
78 return ((struct sockaddr *) ss)->sa_family;
79}
80
81
82/**
83 * Return the DNS name of the client.
84 *
85 * The name is statically cached so that repeated lookups are quick,
86 * so there is a limit of one lookup per customer.
87 *
88 * If anything goes wrong, including the name->addr->name check, then
89 * we just use "UNKNOWN", so you can use that value in hosts allow
90 * lines.
6c92af20
MP
91 *
92 * After translation from sockaddr to name we do a forward lookup to
93 * make sure nobody is spoofing PTR records.
0cd2f407
MP
94 **/
95char *client_name(int fd)
96{
0cd2f407
MP
97 static char name_buf[100];
98 static char port_buf[100];
99 static int initialised;
706c7530 100 struct sockaddr_storage ss;
1e736b8f 101 socklen_t ss_len;
0cd2f407 102
4cfa6156
WD
103 if (initialised)
104 return name_buf;
0cd2f407
MP
105
106 strcpy(name_buf, default_name);
107 initialised = 1;
108
706c7530
WD
109 memset(&ss, 0, sizeof ss);
110
2b284ee3 111 if (am_server) { /* daemon over --rsh mode */
1e736b8f 112 char *addr = client_addr(fd);
706c7530
WD
113 struct addrinfo hint, *answer;
114 int err;
1e736b8f 115
706c7530
WD
116 memset(&hint, 0, sizeof hint);
117
6a6d2113 118#ifdef AI_NUMERICHOST
706c7530 119 hint.ai_flags = AI_NUMERICHOST;
6a6d2113 120#endif
706c7530
WD
121 hint.ai_socktype = SOCK_STREAM;
122
123 if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
fde045cd 124 rprintf(FLOG, "malformed address %s: %s\n",
706c7530
WD
125 addr, gai_strerror(err));
126 return name_buf;
1e736b8f 127 }
706c7530
WD
128
129 switch (answer->ai_family) {
130 case AF_INET:
131 ss_len = sizeof (struct sockaddr_in);
132 memcpy(&ss, answer->ai_addr, ss_len);
133 break;
4f5b0756 134#ifdef INET6
706c7530
WD
135 case AF_INET6:
136 ss_len = sizeof (struct sockaddr_in6);
137 memcpy(&ss, answer->ai_addr, ss_len);
138 break;
a6d8c3f3 139#endif
1e736b8f 140 }
706c7530 141 freeaddrinfo(answer);
09021eab 142 } else {
1e736b8f 143 ss_len = sizeof ss;
09021eab 144 client_sockaddr(fd, &ss, &ss_len);
09021eab 145 }
0cd2f407 146
fde045cd
WD
147 if (lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
148 port_buf, sizeof port_buf) == 0)
706c7530 149 check_name(fd, &ss, name_buf);
1e736b8f 150
0cd2f407
MP
151 return name_buf;
152}
153
154
155
156/**
af32f69e
MP
157 * Get the sockaddr for the client.
158 *
159 * If it comes in as an ipv4 address mapped into IPv6 format then we
160 * convert it back to a regular IPv4.
0cd2f407
MP
161 **/
162void client_sockaddr(int fd,
163 struct sockaddr_storage *ss,
164 socklen_t *ss_len)
165{
c1e7217f 166 memset(ss, 0, sizeof *ss);
bc2b4963 167
0cd2f407
MP
168 if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
169 /* FIXME: Can we really not continue? */
fde045cd 170 rsyserr(FLOG, errno, "getpeername on fd%d failed", fd);
0cd2f407
MP
171 exit_cleanup(RERR_SOCKETIO);
172 }
173
4f5b0756 174#ifdef INET6
2b284ee3 175 if (get_sockaddr_family(ss) == AF_INET6 &&
0cd2f407
MP
176 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
177 /* OK, so ss is in the IPv6 family, but it is really
178 * an IPv4 address: something like
179 * "::ffff:10.130.1.2". If we use it as-is, then the
180 * reverse lookup might fail or perhaps something else
181 * bad might happen. So instead we convert it to an
182 * equivalent address in the IPv4 address family. */
183 struct sockaddr_in6 sin6;
184 struct sockaddr_in *sin;
185
c1e7217f 186 memcpy(&sin6, ss, sizeof sin6);
0cd2f407 187 sin = (struct sockaddr_in *)ss;
c1e7217f 188 memset(sin, 0, sizeof *sin);
0cd2f407 189 sin->sin_family = AF_INET;
c1e7217f 190 *ss_len = sizeof (struct sockaddr_in);
4f5b0756 191#ifdef HAVE_SOCKADDR_IN_LEN
0cd2f407
MP
192 sin->sin_len = *ss_len;
193#endif
194 sin->sin_port = sin6.sin6_port;
195
196 /* There is a macro to extract the mapped part
197 * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
198 * to be present in the Linux headers. */
199 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
c1e7217f 200 sizeof sin->sin_addr);
2b284ee3 201 }
0cd2f407
MP
202#endif
203}
204
205
206/**
207 * Look up a name from @p ss into @p name_buf.
6c92af20
MP
208 *
209 * @param fd file descriptor for client socket.
0cd2f407
MP
210 **/
211int lookup_name(int fd, const struct sockaddr_storage *ss,
212 socklen_t ss_len,
213 char *name_buf, size_t name_buf_len,
214 char *port_buf, size_t port_buf_len)
215{
216 int name_err;
4cfa6156 217
0cd2f407
MP
218 /* reverse lookup */
219 name_err = getnameinfo((struct sockaddr *) ss, ss_len,
220 name_buf, name_buf_len,
221 port_buf, port_buf_len,
222 NI_NAMEREQD | NI_NUMERICSERV);
223 if (name_err != 0) {
224 strcpy(name_buf, default_name);
fde045cd
WD
225 rprintf(FLOG, "name lookup failed for %s: %s\n",
226 client_addr(fd), gai_strerror(name_err));
0cd2f407
MP
227 return name_err;
228 }
229
230 return 0;
231}
232
233
234
974f27e7
MP
235/**
236 * Compare an addrinfo from the resolver to a sockinfo.
237 *
238 * Like strcmp, returns 0 for identical.
239 **/
240int compare_addrinfo_sockaddr(const struct addrinfo *ai,
241 const struct sockaddr_storage *ss)
242{
243 int ss_family = get_sockaddr_family(ss);
244 const char fn[] = "compare_addrinfo_sockaddr";
c1e7217f 245
974f27e7 246 if (ai->ai_family != ss_family) {
fde045cd 247 rprintf(FLOG, "%s: response family %d != %d\n",
974f27e7
MP
248 fn, ai->ai_family, ss_family);
249 return 1;
250 }
251
39e01d2d
MP
252 /* The comparison method depends on the particular AF. */
253 if (ss_family == AF_INET) {
254 const struct sockaddr_in *sin1, *sin2;
255
256 sin1 = (const struct sockaddr_in *) ss;
257 sin2 = (const struct sockaddr_in *) ai->ai_addr;
4cfa6156 258
6780f720
MP
259 return memcmp(&sin1->sin_addr, &sin2->sin_addr,
260 sizeof sin1->sin_addr);
39e01d2d 261 }
2b284ee3 262
4f5b0756 263#ifdef INET6
2b284ee3 264 if (ss_family == AF_INET6) {
6780f720
MP
265 const struct sockaddr_in6 *sin1, *sin2;
266
267 sin1 = (const struct sockaddr_in6 *) ss;
268 sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
bc2b4963 269
c1e7217f 270 if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
fde045cd 271 rprintf(FLOG, "%s: too short sockaddr_in6; length=%d\n",
bc2b4963
DD
272 fn, ai->ai_addrlen);
273 return 1;
274 }
275
276 if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
277 sizeof sin1->sin6_addr))
278 return 1;
279
4f5b0756 280#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
bc2b4963
DD
281 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
282 return 1;
283#endif
284 return 0;
39e01d2d
MP
285 }
286#endif /* INET6 */
2b284ee3
WD
287
288 /* don't know */
289 return 1;
974f27e7
MP
290}
291
292
af32f69e
MP
293/**
294 * Do a forward lookup on @p name_buf and make sure it corresponds to
295 * @p ss -- otherwise we may be being spoofed. If we suspect we are,
296 * then we don't abort the connection but just emit a warning, and
297 * change @p name_buf to be "UNKNOWN".
6c92af20
MP
298 *
299 * We don't do anything with the service when checking the name,
300 * because it doesn't seem that it could be spoofed in any way, and
301 * getaddrinfo on random service names seems to cause problems on AIX.
af32f69e 302 **/
0cd2f407
MP
303int check_name(int fd,
304 const struct sockaddr_storage *ss,
6c92af20 305 char *name_buf)
0cd2f407
MP
306{
307 struct addrinfo hints, *res, *res0;
308 int error;
309 int ss_family = get_sockaddr_family(ss);
310
c1e7217f 311 memset(&hints, 0, sizeof hints);
39e01d2d
MP
312 hints.ai_family = ss_family;
313 hints.ai_flags = AI_CANONNAME;
0cd2f407 314 hints.ai_socktype = SOCK_STREAM;
6c92af20 315 error = getaddrinfo(name_buf, NULL, &hints, &res0);
0cd2f407 316 if (error) {
fde045cd 317 rprintf(FLOG, "forward name lookup for %s failed: %s\n",
af32f69e 318 name_buf, gai_strerror(error));
0cd2f407
MP
319 strcpy(name_buf, default_name);
320 return error;
321 }
322
974f27e7
MP
323 /* Given all these results, we expect that one of them will be
324 * the same as ss. The comparison is a bit complicated. */
0cd2f407 325 for (res = res0; res; res = res->ai_next) {
974f27e7
MP
326 if (!compare_addrinfo_sockaddr(res, ss))
327 break; /* OK, identical */
0cd2f407
MP
328 }
329
330 if (!res0) {
331 /* We hit the end of the list without finding an
332 * address that was the same as ss. */
fde045cd
WD
333 rprintf(FLOG, "no known address for \"%s\": "
334 "spoofed address?\n", name_buf);
0cd2f407 335 strcpy(name_buf, default_name);
974f27e7 336 } else if (res == NULL) {
0cd2f407
MP
337 /* We hit the end of the list without finding an
338 * address that was the same as ss. */
fde045cd
WD
339 rprintf(FLOG, "%s is not a known address for \"%s\": "
340 "spoofed address?\n", client_addr(fd), name_buf);
0cd2f407
MP
341 strcpy(name_buf, default_name);
342 }
343
344 freeaddrinfo(res0);
345 return 0;
346}