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; 6798937Sdes 6898937Sdes if (getsockname(sd, sa, &salen) == -1) 6998937Sdes return -1; /* errno is correctly set */ 7098937Sdes 7198937Sdes af = sa->sa_family; 7298937Sdes memset(&myaddr, 0, salen); 7398937Sdes } else 7498937Sdes af = sa->sa_family; 7598937Sdes 7698937Sdes if (af == AF_INET) { 77181111Sdes in = (struct sockaddr_in *)sa; 7898937Sdes salen = sizeof(struct sockaddr_in); 79181111Sdes portp = &in->sin_port; 8098937Sdes } else if (af == AF_INET6) { 81181111Sdes in6 = (struct sockaddr_in6 *)sa; 8298937Sdes salen = sizeof(struct sockaddr_in6); 83181111Sdes portp = &in6->sin6_port; 8498937Sdes } else { 8598937Sdes errno = EPFNOSUPPORT; 8698937Sdes return (-1); 8798937Sdes } 8898937Sdes sa->sa_family = af; 8998937Sdes 9098937Sdes port = ntohs(*portp); 9198937Sdes if (port == 0) 92221420Sdes port = arc4random_uniform(NPORTS) + STARTPORT; 9398937Sdes 9498937Sdes /* Avoid warning */ 9598937Sdes error = -1; 9698937Sdes 9798937Sdes for(i = 0; i < NPORTS; i++) { 9898937Sdes *portp = htons(port); 9998937Sdes 10098937Sdes error = bind(sd, sa, salen); 10198937Sdes 10298937Sdes /* Terminate on success */ 10398937Sdes if (error == 0) 10498937Sdes break; 10598937Sdes 10698937Sdes /* Terminate on errors, except "address already in use" */ 10798937Sdes if ((error < 0) && !((errno == EADDRINUSE) || (errno == EINVAL))) 10898937Sdes break; 10998937Sdes 11098937Sdes port++; 11198937Sdes if (port > ENDPORT) 11298937Sdes port = STARTPORT; 11398937Sdes } 11498937Sdes 11598937Sdes return (error); 11698937Sdes} 11798937Sdes 11898937Sdes#endif /* HAVE_BINDRESVPORT_SA */ 119