1124208Sdes/* This file has be substantially modified from the original OpenBSD source */
298937Sdes
3181111Sdes/*	$OpenBSD: bindresvport.c,v 1.17 2005/12/21 01:40:22 millert 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
36162852Sdes#include <sys/types.h>
37162852Sdes#include <sys/socket.h>
3898937Sdes
39162852Sdes#include <netinet/in.h>
40162852Sdes#include <arpa/inet.h>
4198937Sdes
42162852Sdes#include <errno.h>
43162852Sdes#include <string.h>
44162852Sdes
4598937Sdes#define STARTPORT 600
4698937Sdes#define ENDPORT (IPPORT_RESERVED - 1)
4798937Sdes#define NPORTS	(ENDPORT - STARTPORT + 1)
4898937Sdes
4998937Sdes/*
5098937Sdes * Bind a socket to a privileged IP port
5198937Sdes */
5298937Sdesint
53157016Sdesbindresvport_sa(int sd, struct sockaddr *sa)
5498937Sdes{
5598937Sdes	int error, af;
5698937Sdes	struct sockaddr_storage myaddr;
57181111Sdes	struct sockaddr_in *in;
58181111Sdes	struct sockaddr_in6 *in6;
5998937Sdes	u_int16_t *portp;
6098937Sdes	u_int16_t port;
6198937Sdes	socklen_t salen;
6298937Sdes	int i;
6398937Sdes
6498937Sdes	if (sa == NULL) {
6598937Sdes		memset(&myaddr, 0, sizeof(myaddr));
6698937Sdes		sa = (struct sockaddr *)&myaddr;
67323124Sdes		salen = sizeof(myaddr);
6898937Sdes
6998937Sdes		if (getsockname(sd, sa, &salen) == -1)
7098937Sdes			return -1;	/* errno is correctly set */
7198937Sdes
7298937Sdes		af = sa->sa_family;
7398937Sdes		memset(&myaddr, 0, salen);
7498937Sdes	} else
7598937Sdes		af = sa->sa_family;
7698937Sdes
7798937Sdes	if (af == AF_INET) {
78181111Sdes		in = (struct sockaddr_in *)sa;
7998937Sdes		salen = sizeof(struct sockaddr_in);
80181111Sdes		portp = &in->sin_port;
8198937Sdes	} else if (af == AF_INET6) {
82181111Sdes		in6 = (struct sockaddr_in6 *)sa;
8398937Sdes		salen = sizeof(struct sockaddr_in6);
84181111Sdes		portp = &in6->sin6_port;
8598937Sdes	} else {
8698937Sdes		errno = EPFNOSUPPORT;
8798937Sdes		return (-1);
8898937Sdes	}
8998937Sdes	sa->sa_family = af;
9098937Sdes
9198937Sdes	port = ntohs(*portp);
9298937Sdes	if (port == 0)
93221420Sdes		port = arc4random_uniform(NPORTS) + STARTPORT;
9498937Sdes
9598937Sdes	/* Avoid warning */
9698937Sdes	error = -1;
9798937Sdes
9898937Sdes	for(i = 0; i < NPORTS; i++) {
9998937Sdes		*portp = htons(port);
10098937Sdes
10198937Sdes		error = bind(sd, sa, salen);
10298937Sdes
10398937Sdes		/* Terminate on success */
10498937Sdes		if (error == 0)
10598937Sdes			break;
10698937Sdes
10798937Sdes		/* Terminate on errors, except "address already in use" */
10898937Sdes		if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL)))
10998937Sdes			break;
11098937Sdes
11198937Sdes		port++;
11298937Sdes		if (port > ENDPORT)
11398937Sdes			port = STARTPORT;
11498937Sdes	}
11598937Sdes
11698937Sdes	return (error);
11798937Sdes}
11898937Sdes
11998937Sdes#endif /* HAVE_BINDRESVPORT_SA */
120