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