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