Changed rprintf() calls that included strerror() to use rsyserr().
[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
DD
37extern int am_daemon;
38extern int am_server;
0cd2f407
MP
39
40
41/**
c1e7217f 42 * Return the IP addr of the client as a string
0cd2f407
MP
43 **/
44char *client_addr(int fd)
45{
46 struct sockaddr_storage ss;
47 socklen_t length = sizeof ss;
09021eab 48 char *ssh_client, *p;
542ad675 49 int len;
0cd2f407
MP
50 static char addr_buf[100];
51 static int initialised;
52
4cfa6156
WD
53 if (initialised)
54 return addr_buf;
0cd2f407
MP
55
56 initialised = 1;
57
706c7530 58 if (am_server) { /* daemon over --rsh mode */
542ad675
DD
59 strcpy(addr_buf, "0.0.0.0");
60 if ((ssh_client = getenv("SSH_CLIENT")) != NULL) {
61 /* truncate SSH_CLIENT to just IP address */
2b284ee3 62 if ((p = strchr(ssh_client, ' ')) != NULL) {
c1e7217f
WD
63 len = MIN((unsigned int) (p - ssh_client),
64 sizeof addr_buf - 1);
542ad675
DD
65 strncpy(addr_buf, ssh_client, len);
66 *(addr_buf + len) = '\0';
67 }
68 }
3b5f6214 69 } else {
09021eab 70 client_sockaddr(fd, &ss, &length);
3b5f6214
WD
71 getnameinfo((struct sockaddr *)&ss, length,
72 addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST);
73 }
09021eab 74
0cd2f407
MP
75 return addr_buf;
76}
77
78
79static int get_sockaddr_family(const struct sockaddr_storage *ss)
80{
81 return ((struct sockaddr *) ss)->sa_family;
82}
83
84
85/**
86 * Return the DNS name of the client.
87 *
88 * The name is statically cached so that repeated lookups are quick,
89 * so there is a limit of one lookup per customer.
90 *
91 * If anything goes wrong, including the name->addr->name check, then
92 * we just use "UNKNOWN", so you can use that value in hosts allow
93 * lines.
6c92af20
MP
94 *
95 * After translation from sockaddr to name we do a forward lookup to
96 * make sure nobody is spoofing PTR records.
0cd2f407
MP
97 **/
98char *client_name(int fd)
99{
0cd2f407
MP
100 static char name_buf[100];
101 static char port_buf[100];
102 static int initialised;
706c7530 103 struct sockaddr_storage ss;
1e736b8f 104 socklen_t ss_len;
0cd2f407 105
4cfa6156
WD
106 if (initialised)
107 return name_buf;
0cd2f407
MP
108
109 strcpy(name_buf, default_name);
110 initialised = 1;
111
706c7530
WD
112 memset(&ss, 0, sizeof ss);
113
2b284ee3 114 if (am_server) { /* daemon over --rsh mode */
1e736b8f 115 char *addr = client_addr(fd);
706c7530
WD
116 struct addrinfo hint, *answer;
117 int err;
1e736b8f 118
706c7530
WD
119 memset(&hint, 0, sizeof hint);
120
6a6d2113 121#ifdef AI_NUMERICHOST
706c7530 122 hint.ai_flags = AI_NUMERICHOST;
6a6d2113 123#endif
706c7530
WD
124 hint.ai_socktype = SOCK_STREAM;
125
126 if ((err = getaddrinfo(addr, NULL, &hint, &answer)) != 0) {
127 rprintf(FERROR, RSYNC_NAME ": malformed address %s: %s\n",
128 addr, gai_strerror(err));
129 return name_buf;
1e736b8f 130 }
706c7530
WD
131
132 switch (answer->ai_family) {
133 case AF_INET:
134 ss_len = sizeof (struct sockaddr_in);
135 memcpy(&ss, answer->ai_addr, ss_len);
136 break;
137#ifdef INET6
138 case AF_INET6:
139 ss_len = sizeof (struct sockaddr_in6);
140 memcpy(&ss, answer->ai_addr, ss_len);
141 break;
a6d8c3f3 142#endif
1e736b8f 143 }
706c7530 144 freeaddrinfo(answer);
09021eab 145 } else {
1e736b8f 146 ss_len = sizeof ss;
09021eab 147 client_sockaddr(fd, &ss, &ss_len);
09021eab 148 }
0cd2f407 149
706c7530 150 if (!lookup_name(fd, &ss, ss_len, name_buf, sizeof name_buf,
1e736b8f 151 port_buf, sizeof port_buf))
706c7530 152 check_name(fd, &ss, name_buf);
1e736b8f 153
0cd2f407
MP
154 return name_buf;
155}
156
157
158
159/**
af32f69e
MP
160 * Get the sockaddr for the client.
161 *
162 * If it comes in as an ipv4 address mapped into IPv6 format then we
163 * convert it back to a regular IPv4.
0cd2f407
MP
164 **/
165void client_sockaddr(int fd,
166 struct sockaddr_storage *ss,
167 socklen_t *ss_len)
168{
c1e7217f 169 memset(ss, 0, sizeof *ss);
bc2b4963 170
0cd2f407
MP
171 if (getpeername(fd, (struct sockaddr *) ss, ss_len)) {
172 /* FIXME: Can we really not continue? */
d62bcc17 173 rsyserr(FERROR, errno, "getpeername on fd%d failed", fd);
0cd2f407
MP
174 exit_cleanup(RERR_SOCKETIO);
175 }
176
177#ifdef INET6
2b284ee3 178 if (get_sockaddr_family(ss) == AF_INET6 &&
0cd2f407
MP
179 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
180 /* OK, so ss is in the IPv6 family, but it is really
181 * an IPv4 address: something like
182 * "::ffff:10.130.1.2". If we use it as-is, then the
183 * reverse lookup might fail or perhaps something else
184 * bad might happen. So instead we convert it to an
185 * equivalent address in the IPv4 address family. */
186 struct sockaddr_in6 sin6;
187 struct sockaddr_in *sin;
188
c1e7217f 189 memcpy(&sin6, ss, sizeof sin6);
0cd2f407 190 sin = (struct sockaddr_in *)ss;
c1e7217f 191 memset(sin, 0, sizeof *sin);
0cd2f407 192 sin->sin_family = AF_INET;
c1e7217f 193 *ss_len = sizeof (struct sockaddr_in);
16f72adc 194#if HAVE_SOCKADDR_IN_LEN
0cd2f407
MP
195 sin->sin_len = *ss_len;
196#endif
197 sin->sin_port = sin6.sin6_port;
198
199 /* There is a macro to extract the mapped part
200 * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
201 * to be present in the Linux headers. */
202 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
c1e7217f 203 sizeof sin->sin_addr);
2b284ee3 204 }
0cd2f407
MP
205#endif
206}
207
208
209/**
210 * Look up a name from @p ss into @p name_buf.
6c92af20
MP
211 *
212 * @param fd file descriptor for client socket.
0cd2f407
MP
213 **/
214int lookup_name(int fd, const struct sockaddr_storage *ss,
215 socklen_t ss_len,
216 char *name_buf, size_t name_buf_len,
217 char *port_buf, size_t port_buf_len)
218{
219 int name_err;
4cfa6156 220
0cd2f407
MP
221 /* reverse lookup */
222 name_err = getnameinfo((struct sockaddr *) ss, ss_len,
223 name_buf, name_buf_len,
224 port_buf, port_buf_len,
225 NI_NAMEREQD | NI_NUMERICSERV);
226 if (name_err != 0) {
227 strcpy(name_buf, default_name);
228 rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
229 client_addr(fd),
230 gai_strerror(name_err));
231 return name_err;
232 }
233
234 return 0;
235}
236
237
238
974f27e7
MP
239/**
240 * Compare an addrinfo from the resolver to a sockinfo.
241 *
242 * Like strcmp, returns 0 for identical.
243 **/
244int compare_addrinfo_sockaddr(const struct addrinfo *ai,
245 const struct sockaddr_storage *ss)
246{
247 int ss_family = get_sockaddr_family(ss);
248 const char fn[] = "compare_addrinfo_sockaddr";
c1e7217f 249
974f27e7
MP
250 if (ai->ai_family != ss_family) {
251 rprintf(FERROR,
252 "%s: response family %d != %d\n",
253 fn, ai->ai_family, ss_family);
254 return 1;
255 }
256
39e01d2d
MP
257 /* The comparison method depends on the particular AF. */
258 if (ss_family == AF_INET) {
259 const struct sockaddr_in *sin1, *sin2;
260
261 sin1 = (const struct sockaddr_in *) ss;
262 sin2 = (const struct sockaddr_in *) ai->ai_addr;
4cfa6156 263
6780f720
MP
264 return memcmp(&sin1->sin_addr, &sin2->sin_addr,
265 sizeof sin1->sin_addr);
39e01d2d 266 }
2b284ee3 267
974f27e7 268#ifdef INET6
2b284ee3 269 if (ss_family == AF_INET6) {
6780f720
MP
270 const struct sockaddr_in6 *sin1, *sin2;
271
272 sin1 = (const struct sockaddr_in6 *) ss;
273 sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
bc2b4963 274
c1e7217f 275 if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
bc2b4963
DD
276 rprintf(FERROR,
277 "%s: too short sockaddr_in6; length=%d\n",
278 fn, ai->ai_addrlen);
279 return 1;
280 }
281
282 if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
283 sizeof sin1->sin6_addr))
284 return 1;
285
286#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
287 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
288 return 1;
289#endif
290 return 0;
39e01d2d
MP
291 }
292#endif /* INET6 */
2b284ee3
WD
293
294 /* don't know */
295 return 1;
974f27e7
MP
296}
297
298
af32f69e
MP
299/**
300 * Do a forward lookup on @p name_buf and make sure it corresponds to
301 * @p ss -- otherwise we may be being spoofed. If we suspect we are,
302 * then we don't abort the connection but just emit a warning, and
303 * change @p name_buf to be "UNKNOWN".
6c92af20
MP
304 *
305 * We don't do anything with the service when checking the name,
306 * because it doesn't seem that it could be spoofed in any way, and
307 * getaddrinfo on random service names seems to cause problems on AIX.
af32f69e 308 **/
0cd2f407
MP
309int check_name(int fd,
310 const struct sockaddr_storage *ss,
6c92af20 311 char *name_buf)
0cd2f407
MP
312{
313 struct addrinfo hints, *res, *res0;
314 int error;
315 int ss_family = get_sockaddr_family(ss);
316
c1e7217f 317 memset(&hints, 0, sizeof hints);
39e01d2d
MP
318 hints.ai_family = ss_family;
319 hints.ai_flags = AI_CANONNAME;
0cd2f407 320 hints.ai_socktype = SOCK_STREAM;
6c92af20 321 error = getaddrinfo(name_buf, NULL, &hints, &res0);
0cd2f407
MP
322 if (error) {
323 rprintf(FERROR,
af32f69e
MP
324 RSYNC_NAME ": forward name lookup for %s failed: %s\n",
325 name_buf, gai_strerror(error));
0cd2f407
MP
326 strcpy(name_buf, default_name);
327 return error;
328 }
329
330
974f27e7
MP
331 /* Given all these results, we expect that one of them will be
332 * the same as ss. The comparison is a bit complicated. */
0cd2f407 333 for (res = res0; res; res = res->ai_next) {
974f27e7
MP
334 if (!compare_addrinfo_sockaddr(res, ss))
335 break; /* OK, identical */
0cd2f407
MP
336 }
337
338 if (!res0) {
339 /* We hit the end of the list without finding an
340 * address that was the same as ss. */
341 rprintf(FERROR, RSYNC_NAME
342 ": no known address for \"%s\": "
343 "spoofed address?\n",
344 name_buf);
345 strcpy(name_buf, default_name);
974f27e7 346 } else if (res == NULL) {
0cd2f407
MP
347 /* We hit the end of the list without finding an
348 * address that was the same as ss. */
349 rprintf(FERROR, RSYNC_NAME
350 ": %s is not a known address for \"%s\": "
351 "spoofed address?\n",
352 client_addr(fd),
353 name_buf);
354 strcpy(name_buf, default_name);
355 }
356
357 freeaddrinfo(res0);
358 return 0;
359}
360