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? */
173 rprintf(FERROR, RSYNC_NAME ": getpeername on fd%d failed: %s\n",
174 fd, strerror(errno));
175 exit_cleanup(RERR_SOCKETIO);
176 }
177
178#ifdef INET6
2b284ee3 179 if (get_sockaddr_family(ss) == AF_INET6 &&
0cd2f407
MP
180 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)ss)->sin6_addr)) {
181 /* OK, so ss is in the IPv6 family, but it is really
182 * an IPv4 address: something like
183 * "::ffff:10.130.1.2". If we use it as-is, then the
184 * reverse lookup might fail or perhaps something else
185 * bad might happen. So instead we convert it to an
186 * equivalent address in the IPv4 address family. */
187 struct sockaddr_in6 sin6;
188 struct sockaddr_in *sin;
189
c1e7217f 190 memcpy(&sin6, ss, sizeof sin6);
0cd2f407 191 sin = (struct sockaddr_in *)ss;
c1e7217f 192 memset(sin, 0, sizeof *sin);
0cd2f407 193 sin->sin_family = AF_INET;
c1e7217f 194 *ss_len = sizeof (struct sockaddr_in);
16f72adc 195#if HAVE_SOCKADDR_IN_LEN
0cd2f407
MP
196 sin->sin_len = *ss_len;
197#endif
198 sin->sin_port = sin6.sin6_port;
199
200 /* There is a macro to extract the mapped part
201 * (IN6_V4MAPPED_TO_SINADDR ?), but it does not seem
202 * to be present in the Linux headers. */
203 memcpy(&sin->sin_addr, &sin6.sin6_addr.s6_addr[12],
c1e7217f 204 sizeof sin->sin_addr);
2b284ee3 205 }
0cd2f407
MP
206#endif
207}
208
209
210/**
211 * Look up a name from @p ss into @p name_buf.
6c92af20
MP
212 *
213 * @param fd file descriptor for client socket.
0cd2f407
MP
214 **/
215int lookup_name(int fd, const struct sockaddr_storage *ss,
216 socklen_t ss_len,
217 char *name_buf, size_t name_buf_len,
218 char *port_buf, size_t port_buf_len)
219{
220 int name_err;
4cfa6156 221
0cd2f407
MP
222 /* reverse lookup */
223 name_err = getnameinfo((struct sockaddr *) ss, ss_len,
224 name_buf, name_buf_len,
225 port_buf, port_buf_len,
226 NI_NAMEREQD | NI_NUMERICSERV);
227 if (name_err != 0) {
228 strcpy(name_buf, default_name);
229 rprintf(FERROR, RSYNC_NAME ": name lookup failed for %s: %s\n",
230 client_addr(fd),
231 gai_strerror(name_err));
232 return name_err;
233 }
234
235 return 0;
236}
237
238
239
974f27e7
MP
240/**
241 * Compare an addrinfo from the resolver to a sockinfo.
242 *
243 * Like strcmp, returns 0 for identical.
244 **/
245int compare_addrinfo_sockaddr(const struct addrinfo *ai,
246 const struct sockaddr_storage *ss)
247{
248 int ss_family = get_sockaddr_family(ss);
249 const char fn[] = "compare_addrinfo_sockaddr";
c1e7217f 250
974f27e7
MP
251 if (ai->ai_family != ss_family) {
252 rprintf(FERROR,
253 "%s: response family %d != %d\n",
254 fn, ai->ai_family, ss_family);
255 return 1;
256 }
257
39e01d2d
MP
258 /* The comparison method depends on the particular AF. */
259 if (ss_family == AF_INET) {
260 const struct sockaddr_in *sin1, *sin2;
261
262 sin1 = (const struct sockaddr_in *) ss;
263 sin2 = (const struct sockaddr_in *) ai->ai_addr;
4cfa6156 264
6780f720
MP
265 return memcmp(&sin1->sin_addr, &sin2->sin_addr,
266 sizeof sin1->sin_addr);
39e01d2d 267 }
2b284ee3 268
974f27e7 269#ifdef INET6
2b284ee3 270 if (ss_family == AF_INET6) {
6780f720
MP
271 const struct sockaddr_in6 *sin1, *sin2;
272
273 sin1 = (const struct sockaddr_in6 *) ss;
274 sin2 = (const struct sockaddr_in6 *) ai->ai_addr;
bc2b4963 275
c1e7217f 276 if (ai->ai_addrlen < sizeof (struct sockaddr_in6)) {
bc2b4963
DD
277 rprintf(FERROR,
278 "%s: too short sockaddr_in6; length=%d\n",
279 fn, ai->ai_addrlen);
280 return 1;
281 }
282
283 if (memcmp(&sin1->sin6_addr, &sin2->sin6_addr,
284 sizeof sin1->sin6_addr))
285 return 1;
286
287#ifdef HAVE_SOCKADDR_IN6_SCOPE_ID
288 if (sin1->sin6_scope_id != sin2->sin6_scope_id)
289 return 1;
290#endif
291 return 0;
39e01d2d
MP
292 }
293#endif /* INET6 */
2b284ee3
WD
294
295 /* don't know */
296 return 1;
974f27e7
MP
297}
298
299
af32f69e
MP
300/**
301 * Do a forward lookup on @p name_buf and make sure it corresponds to
302 * @p ss -- otherwise we may be being spoofed. If we suspect we are,
303 * then we don't abort the connection but just emit a warning, and
304 * change @p name_buf to be "UNKNOWN".
6c92af20
MP
305 *
306 * We don't do anything with the service when checking the name,
307 * because it doesn't seem that it could be spoofed in any way, and
308 * getaddrinfo on random service names seems to cause problems on AIX.
af32f69e 309 **/
0cd2f407
MP
310int check_name(int fd,
311 const struct sockaddr_storage *ss,
6c92af20 312 char *name_buf)
0cd2f407
MP
313{
314 struct addrinfo hints, *res, *res0;
315 int error;
316 int ss_family = get_sockaddr_family(ss);
317
c1e7217f 318 memset(&hints, 0, sizeof hints);
39e01d2d
MP
319 hints.ai_family = ss_family;
320 hints.ai_flags = AI_CANONNAME;
0cd2f407 321 hints.ai_socktype = SOCK_STREAM;
6c92af20 322 error = getaddrinfo(name_buf, NULL, &hints, &res0);
0cd2f407
MP
323 if (error) {
324 rprintf(FERROR,
af32f69e
MP
325 RSYNC_NAME ": forward name lookup for %s failed: %s\n",
326 name_buf, gai_strerror(error));
0cd2f407
MP
327 strcpy(name_buf, default_name);
328 return error;
329 }
330
331
974f27e7
MP
332 /* Given all these results, we expect that one of them will be
333 * the same as ss. The comparison is a bit complicated. */
0cd2f407 334 for (res = res0; res; res = res->ai_next) {
974f27e7
MP
335 if (!compare_addrinfo_sockaddr(res, ss))
336 break; /* OK, identical */
0cd2f407
MP
337 }
338
339 if (!res0) {
340 /* We hit the end of the list without finding an
341 * address that was the same as ss. */
342 rprintf(FERROR, RSYNC_NAME
343 ": no known address for \"%s\": "
344 "spoofed address?\n",
345 name_buf);
346 strcpy(name_buf, default_name);
974f27e7 347 } else if (res == NULL) {
0cd2f407
MP
348 /* We hit the end of the list without finding an
349 * address that was the same as ss. */
350 rprintf(FERROR, RSYNC_NAME
351 ": %s is not a known address for \"%s\": "
352 "spoofed address?\n",
353 client_addr(fd),
354 name_buf);
355 strcpy(name_buf, default_name);
356 }
357
358 freeaddrinfo(res0);
359 return 0;
360}
361