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