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