bindresvport.c revision 157016
1124208Sdes/* This file has be substantially modified from the original OpenBSD source */
298937Sdes
3157016Sdes/*	$OpenBSD: bindresvport.c,v 1.16 2005/04/01 07:44:03 otto Exp $	*/
4124208Sdes
598937Sdes/*
6124208Sdes * Copyright 1996, Jason Downs.  All rights reserved.
7124208Sdes * Copyright 1998, Theo de Raadt.  All rights reserved.
8124208Sdes * Copyright 2000, Damien Miller.  All rights reserved.
9124208Sdes *
10124208Sdes * Redistribution and use in source and binary forms, with or without
11124208Sdes * modification, are permitted provided that the following conditions
12124208Sdes * are met:
13124208Sdes * 1. Redistributions of source code must retain the above copyright
14124208Sdes *    notice, this list of conditions and the following disclaimer.
15124208Sdes * 2. Redistributions in binary form must reproduce the above copyright
16124208Sdes *    notice, this list of conditions and the following disclaimer in the
17124208Sdes *    documentation and/or other materials provided with the distribution.
18124208Sdes *
19124208Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20124208Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21124208Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22124208Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23124208Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24124208Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25124208Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26124208Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27124208Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28124208Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2998937Sdes */
3098937Sdes
31157016Sdes/* OPENBSD ORIGINAL: lib/libc/rpc/bindresvport.c */
32157016Sdes
33106121Sdes#include "includes.h"
3498937Sdes
3598937Sdes#ifndef HAVE_BINDRESVPORT_SA
3698937Sdes
3798937Sdes#include "includes.h"
3898937Sdes
3998937Sdes#define STARTPORT 600
4098937Sdes#define ENDPORT (IPPORT_RESERVED - 1)
4198937Sdes#define NPORTS	(ENDPORT - STARTPORT + 1)
4298937Sdes
4398937Sdes/*
4498937Sdes * Bind a socket to a privileged IP port
4598937Sdes */
4698937Sdesint
47157016Sdesbindresvport_sa(int sd, struct sockaddr *sa)
4898937Sdes{
4998937Sdes	int error, af;
5098937Sdes	struct sockaddr_storage myaddr;
5198937Sdes	struct sockaddr_in *sin;
5298937Sdes	struct sockaddr_in6 *sin6;
5398937Sdes	u_int16_t *portp;
5498937Sdes	u_int16_t port;
5598937Sdes	socklen_t salen;
5698937Sdes	int i;
5798937Sdes
5898937Sdes	if (sa == NULL) {
5998937Sdes		memset(&myaddr, 0, sizeof(myaddr));
6098937Sdes		sa = (struct sockaddr *)&myaddr;
6198937Sdes
6298937Sdes		if (getsockname(sd, sa, &salen) == -1)
6398937Sdes			return -1;	/* errno is correctly set */
6498937Sdes
6598937Sdes		af = sa->sa_family;
6698937Sdes		memset(&myaddr, 0, salen);
6798937Sdes	} else
6898937Sdes		af = sa->sa_family;
6998937Sdes
7098937Sdes	if (af == AF_INET) {
7198937Sdes		sin = (struct sockaddr_in *)sa;
7298937Sdes		salen = sizeof(struct sockaddr_in);
7398937Sdes		portp = &sin->sin_port;
7498937Sdes	} else if (af == AF_INET6) {
7598937Sdes		sin6 = (struct sockaddr_in6 *)sa;
7698937Sdes		salen = sizeof(struct sockaddr_in6);
7798937Sdes		portp = &sin6->sin6_port;
7898937Sdes	} else {
7998937Sdes		errno = EPFNOSUPPORT;
8098937Sdes		return (-1);
8198937Sdes	}
8298937Sdes	sa->sa_family = af;
8398937Sdes
8498937Sdes	port = ntohs(*portp);
8598937Sdes	if (port == 0)
8698937Sdes		port = (arc4random() % NPORTS) + STARTPORT;
8798937Sdes
8898937Sdes	/* Avoid warning */
8998937Sdes	error = -1;
9098937Sdes
9198937Sdes	for(i = 0; i < NPORTS; i++) {
9298937Sdes		*portp = htons(port);
9398937Sdes
9498937Sdes		error = bind(sd, sa, salen);
9598937Sdes
9698937Sdes		/* Terminate on success */
9798937Sdes		if (error == 0)
9898937Sdes			break;
9998937Sdes
10098937Sdes		/* Terminate on errors, except "address already in use" */
10198937Sdes		if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL)))
10298937Sdes			break;
10398937Sdes
10498937Sdes		port++;
10598937Sdes		if (port > ENDPORT)
10698937Sdes			port = STARTPORT;
10798937Sdes	}
10898937Sdes
10998937Sdes	return (error);
11098937Sdes}
11198937Sdes
11298937Sdes#endif /* HAVE_BINDRESVPORT_SA */
113