GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/rpc_fwd.c Lines: 0 67 0.0 %
Date: 2017-11-07 Branches: 0 46 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1989 Jan-Simon Pendry
3
 * Copyright (c) 1989 Imperial College of Science, Technology & Medicine
4
 * Copyright (c) 1989, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Jan-Simon Pendry at Imperial College, London.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	from: @(#)rpc_fwd.c	8.1 (Berkeley) 6/6/93
35
 *	$Id: rpc_fwd.c,v 1.10 2015/09/13 15:44:47 guenther Exp $
36
 */
37
38
/*
39
 * RPC packet forwarding
40
 */
41
42
#include "am.h"
43
#include <sys/ioctl.h>
44
45
/*
46
 * Note that the ID field in the external packet is only
47
 * ever treated as a 32 bit opaque data object, so there
48
 * is no need to convert to and from network byte ordering.
49
 */
50
51
/*
52
 * Each pending reply has an rpc_forward structure
53
 * associated with it.  These have a 15 second lifespan.
54
 * If a new structure is required, then an expired
55
 * one will be re-allocated if available, otherwise a fresh
56
 * one is allocated.  Whenever a reply is received the
57
 * structure is discarded.
58
 */
59
typedef struct rpc_forward rpc_forward;
60
struct rpc_forward {
61
	qelem	rf_q;		/* Linked list */
62
	time_t	rf_ttl;		/* Time to live */
63
	u_int	rf_xid;		/* Packet id */
64
	u_int	rf_oldid;	/* Original packet id */
65
	fwd_fun	rf_fwd;		/* Forwarding function */
66
	void *	rf_ptr;
67
	struct sockaddr_in rf_sin;
68
};
69
70
/*
71
 * Head of list of pending replies
72
 */
73
extern qelem rpc_head;
74
qelem rpc_head = { &rpc_head, &rpc_head };
75
76
static u_int xid;
77
#define	XID_ALLOC()	(xid++)
78
79
#define	MAX_PACKET_SIZE	8192	/* Maximum UDP packet size */
80
81
int fwd_sock;
82
83
/*
84
 * Allocate a rely structure
85
 */
86
static rpc_forward *
87
fwd_alloc()
88
{
89
	time_t now = clocktime();
90
	rpc_forward *p = 0, *p2;
91
92
#ifdef DEBUG
93
	/*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
94
#endif /* DEBUG */
95
	/*
96
	 * First search for an existing expired one.
97
	 */
98
	ITER(p2, rpc_forward, &rpc_head) {
99
		if (p2->rf_ttl <= now) {
100
			p = p2;
101
			break;
102
		}
103
	}
104
105
	/*
106
	 * If one couldn't be found then allocate
107
	 * a new structure and link it at the
108
	 * head of the list.
109
	 */
110
	if (p) {
111
		/*
112
		 * Call forwarding function to say that
113
		 * this message was junked.
114
		 */
115
#ifdef DEBUG
116
		dlog("Re-using packet forwarding slot - id %#x", p->rf_xid);
117
#endif /* DEBUG */
118
		if (p->rf_fwd)
119
			(*p->rf_fwd)(0, 0, 0, &p->rf_sin, p->rf_ptr, FALSE);
120
		rem_que(&p->rf_q);
121
	} else {
122
		p = ALLOC(rpc_forward);
123
	}
124
	ins_que(&p->rf_q, &rpc_head);
125
126
	/*
127
	 * Set the time to live field
128
	 * Timeout in 43 seconds
129
	 */
130
	p->rf_ttl = now + 43;
131
132
#ifdef DEBUG
133
	/*dlog("fwd_alloca: rpc_head = %#x", rpc_head.q_forw);*/
134
#endif /* DEBUG */
135
	return p;
136
}
137
138
/*
139
 * Free an allocated reply structure.
140
 * First unlink it from the list, then
141
 * discard it.
142
 */
143
static void
144
fwd_free(rpc_forward *p)
145
{
146
#ifdef DEBUG
147
	/*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
148
#endif /* DEBUG */
149
	rem_que(&p->rf_q);
150
#ifdef DEBUG
151
	/*dlog("fwd_free: rpc_head = %#x", rpc_head.q_forw);*/
152
#endif /* DEBUG */
153
	free(p);
154
}
155
156
/*
157
 * Initialise the RPC forwarder
158
 */
159
int fwd_init()
160
{
161
	/*
162
	 * Create ping socket
163
	 */
164
	fwd_sock = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0);
165
	if (fwd_sock < 0) {
166
		plog(XLOG_ERROR, "Unable to create RPC forwarding socket: %m");
167
		return errno;
168
	}
169
170
	/*
171
	 * Some things we talk to require a priv port - so make one here
172
	 */
173
	if (bind_resv_port(fwd_sock, (unsigned short *) 0) < 0)
174
		plog(XLOG_ERROR, "can't bind privileged port");
175
176
	return 0;
177
}
178
179
/*
180
 * Locate a packet in the forwarding list
181
 */
182
static rpc_forward *
183
fwd_locate(u_int id)
184
{
185
	rpc_forward *p;
186
187
	ITER(p, rpc_forward, &rpc_head) {
188
		if (p->rf_xid == id)
189
			return p;
190
	}
191
192
	return 0;
193
}
194
195
/*
196
 * This is called to forward a packet to another
197
 * RPC server.  The message id is changed and noted
198
 * so that when a reply appears we can tie it up
199
 * correctly.  Just matching the reply's source address
200
 * would not work because it might come from a
201
 * different address.
202
 */
203
int
204
fwd_packet(int type_id, void *pkt, int len, struct sockaddr_in *fwdto,
205
    struct sockaddr_in *replyto, void *i, fwd_fun cb)
206
{
207
	rpc_forward *p;
208
	u_int *pkt_int;
209
	int error;
210
211
	if ((int)amd_state >= (int)Finishing)
212
		return ENOENT;
213
214
	/*
215
	 * See if the type_id is fully specified.
216
	 * If so, then discard any old entries
217
	 * for this id.
218
	 * Otherwise make sure the type_id is
219
	 * fully qualified by allocating an id here.
220
	 */
221
#ifdef DEBUG
222
	switch (type_id & RPC_XID_MASK) {
223
	case RPC_XID_PORTMAP: dlog("Sending PORTMAP request"); break;
224
	case RPC_XID_MOUNTD: dlog("Sending MOUNTD request %#x", type_id); break;
225
	case RPC_XID_NFSPING: dlog("Sending NFS ping"); break;
226
	default: dlog("UNKNOWN RPC XID"); break;
227
	}
228
#endif /* DEBUG */
229
230
	if (type_id & ~RPC_XID_MASK) {
231
#ifdef DEBUG
232
		/*dlog("Fully qualified rpc type provided");*/
233
#endif /* DEBUG */
234
		p = fwd_locate(type_id);
235
		if (p) {
236
#ifdef DEBUG
237
			dlog("Discarding earlier rpc fwd handle");
238
#endif /* DEBUG */
239
			fwd_free(p);
240
		}
241
	} else {
242
#ifdef DEBUG
243
		dlog("Allocating a new xid...");
244
#endif /* DEBUG */
245
		type_id = MK_RPC_XID(type_id, XID_ALLOC());
246
	}
247
248
	p = fwd_alloc();
249
	if (!p)
250
		return ENOBUFS;
251
252
	error = 0;
253
254
	pkt_int = (u_int *) pkt;
255
256
	/*
257
	 * Get the original packet id
258
	 */
259
	p->rf_oldid = *pkt_int;
260
261
	/*
262
	 * Replace with newly allocated id
263
	 */
264
	p->rf_xid = *pkt_int = type_id;
265
266
	/*
267
	 * The sendto may fail if, for example, the route
268
	 * to a remote host is lost because an intermediate
269
	 * gateway has gone down.  Important to fill in the
270
	 * rest of "p" otherwise nasty things happen later...
271
	 */
272
#ifdef DEBUG
273
	{ char dq[20];
274
275
	dlog("Sending packet id %#x to %s.%d", p->rf_xid,
276
	    inet_dquad(dq, sizeof(dq), fwdto->sin_addr.s_addr),
277
	    ntohs(fwdto->sin_port));
278
	}
279
#endif /* DEBUG */
280
	if (sendto(fwd_sock, (char *) pkt, len, 0,
281
			(struct sockaddr *) fwdto, sizeof(*fwdto)) < 0)
282
		error = errno;
283
284
	/*
285
	 * Save callback function and return address
286
	 */
287
	p->rf_fwd = cb;
288
	if (replyto)
289
		p->rf_sin = *replyto;
290
	else
291
		bzero(&p->rf_sin, sizeof(p->rf_sin));
292
	p->rf_ptr = i;
293
294
	return error;
295
}
296
297
/*
298
 * Called when some data arrives on the forwarding socket
299
 */
300
void
301
fwd_reply()
302
{
303
	int len;
304
#ifdef DYNAMIC_BUFFERS
305
	void *pkt;
306
#else
307
	u_int pkt[MAX_PACKET_SIZE/sizeof(u_int)+1];
308
#endif /* DYNAMIC_BUFFERS */
309
	u_int *pkt_int;
310
	int rc;
311
	rpc_forward *p;
312
	struct sockaddr_in src_addr;
313
	socklen_t src_addr_len;
314
315
	/*
316
	 * Determine the length of the packet
317
	 */
318
#ifdef DYNAMIC_BUFFERS
319
	if (ioctl(fwd_sock, FIONREAD, &len) < 0 || len < 0) {
320
		plog(XLOG_ERROR, "Error reading packet size: %m");
321
		return;
322
	}
323
324
	/*
325
	 * Allocate a buffer
326
	 */
327
	pkt = malloc(len);
328
	if (!pkt) {
329
		plog(XLOG_ERROR, "Out of buffers in fwd_reply");
330
		return;
331
	}
332
#else
333
	len = MAX_PACKET_SIZE;
334
#endif /* DYNAMIC_BUFFERS */
335
336
	/*
337
	 * Read the packet and check for validity
338
	 */
339
again:
340
	src_addr_len = sizeof(src_addr);
341
	rc = recvfrom(fwd_sock, (char *) pkt, len, 0,
342
	    (struct sockaddr *) &src_addr, &src_addr_len);
343
	if (rc < 0 || src_addr_len != sizeof(src_addr) ||
344
			src_addr.sin_family != AF_INET) {
345
		if (rc < 0 && errno == EINTR)
346
			goto again;
347
		plog(XLOG_ERROR, "Error reading RPC reply: %m");
348
		goto out;
349
	}
350
351
#ifdef DYNAMIC_BUFFERS
352
	if (rc != len) {
353
		plog(XLOG_ERROR, "Short read in fwd_reply");
354
		goto out;
355
	}
356
#endif /* DYNAMIC_BUFFERS */
357
358
	/*
359
	 * Do no more work if finishing soon
360
	 */
361
	if ((int)amd_state >= (int)Finishing)
362
		goto out;
363
364
	/*
365
	 * Find packet reference
366
	 */
367
	pkt_int = (u_int *) pkt;
368
369
#ifdef DEBUG
370
	switch (*pkt_int & RPC_XID_MASK) {
371
	case RPC_XID_PORTMAP: dlog("Receiving PORTMAP reply"); break;
372
	case RPC_XID_MOUNTD: dlog("Receiving MOUNTD reply %#x", *pkt_int); break;
373
	case RPC_XID_NFSPING: dlog("Receiving NFS ping %#x", *pkt_int); break;
374
	default: dlog("UNKNOWN RPC XID"); break;
375
	}
376
#endif /* DEBUG */
377
378
	p = fwd_locate(*pkt_int);
379
	if (!p) {
380
#ifdef DEBUG
381
		dlog("Can't forward reply id %#x", *pkt_int);
382
#endif /* DEBUG */
383
		goto out;
384
	}
385
386
	if (p->rf_fwd) {
387
		/*
388
		 * Put the original message id back
389
		 * into the packet.
390
		 */
391
		*pkt_int = p->rf_oldid;
392
393
		/*
394
		 * Call forwarding function
395
		 */
396
		(*p->rf_fwd)(pkt, rc, &src_addr, &p->rf_sin, p->rf_ptr, TRUE);
397
	}
398
399
	/*
400
	 * Free forwarding info
401
	 */
402
	fwd_free(p);
403
404
out:;
405
#ifdef DYNAMIC_BUFFERS
406
	/*
407
	 * Free the packet
408
	 */
409
	free(pkt);
410
#endif /* DYNAMIC_BUFFERS */
411
}