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