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