Skip to content
This repository
Fetching contributors…

Cannot retrieve contributors at this time

file 191 lines (151 sloc) 4.764 kb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

<erl>
out(A) ->
       {ssi, "TAB.inc", "%%",[{"privbind", "choosen"}]}.
</erl>


<div id="entry">

<h1>Binding to privileged ports</h1>

<p>
  A common misfeature found on UN*X operating systems is the
  restriction that only root can bind to ports below 1024.
  Many a dollar has been wasted on workarounds and -often- the results are
  security holes.

</p>
<p>
  Both FreeBSD and Solaris have elegant configuration options to
  turn this feature off. On FreeBSD:

<div class="box">
      <verbatim>
$ sysctl net.inet.ip.portrange.reservedhigh=0
      </verbatim>
</div>

the above is best added to your /etc/sysctl.conf
</p>
<p>
  Similarly on Solaris we can just configure away this misfeature.
  Assuming we want to run Yaws/SSL under a non-root user "erlang" on
  ports 80/443.
</p>
<p>
  On Solaris we can do that easily by granting the specific right to bind
  privileged ports <1024 (and only that) to "erlang" using:
</p>

<div class="box">
      <verbatim>
$ /usr/sbin/usermod -K defaultpriv=basic,net_privaddr erlang
      </verbatim>
</div>

<p>
And check the we get what we want through:
</p>


<div class="box">
      <verbatim>
$ grep erlang /etc/user_attr
erlang::::type=normal;defaultpriv=basic,net_privaddr

      </verbatim>
</div>


<p>
  On Linux, kernels later than 2.6.24, it's possible to do:
</p>
<div class="box">
      <verbatim>
$ setcap 'cap_net_bind_service=+ep' /usr/lib/erlang/erts-5.7.4/bin/beam
      </verbatim>
</div>

<p>
  The above command grants the capability of binding
  privileged ports to beam. Note, you have to grant the priviliges to the
  actual exectuable you are using.
<p>

<p>
  There are a couple
  of other options on Linux. One is to use an auxiliary program
  like authbind <em>http://packages.debian.org/stable/authbind</em>
  or privbind <em>http://sourceforge.net/projects/privbind/</em>
</p>
<p>
  These programs are run by root. Yaws writes its temporary
  JIT compiled files in $HOME/.yaws and this doesn't work that
  well with authbind/privbind. A non root user will try to
  write in /root/.yaws. The solution to this is to set the
  environment variable YAWSHOME. Yaws will then consider that to
  be HOME rather that $HOME.
</p>
<p>
  To start yaws under e.g authbind we can do:
</p>


<div class="box">
      <verbatim>
$ sudo YAWSHOME=/tmp/abc privbind -u klacke /home/klacke/bin/yaws \
    -c /home/klacke/yaws.conf -i

      </verbatim>
</div>

<p>
  The above command starts yaws as user <em>klacke</em> and bind
  to ports below 1024
</p>

<p>
  Yet another option is to is to install fdsrv which is a standalone
  program that has the suid bit set, binds privileged ports and passes
  the filedescriptor to yaws. I have made a package out of the jungerl
  code that can be easily installed just through the usual cycle of
  make && make install The code is at
</p>
<pre>
http://yaws.hyber.org/download/fd_server-2.3.0.tgz
</pre>
<p>
  One major drawback with fdsrv is that it doesn't work for SSL. With
  the case of SSL, one possible solution is to put ssltunnel in
  front of yaws and let yaws bind to 127.0.0.1
</p>
<p>
  All in all the fdsrv option is much worse that the authbind option.
</p>


<p>
Here is a description on how to do this on MacOs X. It's not exactly the same,
since we're still binding to non privileged ports. However,
edit /etc/sysctl and add:
</p>

<pre>
net.inet.ip.forwarding=1
</pre>

<p>
Then with ipfw as the firewall (turn off the gui firewall in system
preferences and manage own rules) use the ipfw rules like these - for
testing on your own box use something like:
</p>

<pre>
ipfw add fwd 127.0.0.1,8080 tcp from any to 127.0.0.1 dst-port 80 in
ipfw add fwd 127.0.0.1,8443 tcp from any to 127.0.0.1 dst-port 443 in
</pre>

<p>
set up yaws to use 8080 and 8443 in yaws.conf and then run as some non
root user. When you browse to http://127.0.0.1 or https://127.0.0.1
you will see your pages that are actually on 8080 and 8443 internally
but will be forwarded via ipfw forwarding.
</p>


<p>

Yet another (more complicated way) for linux users is to hack the kernel.
Here is a patch I did for some version of the 2.6 series kernels .. you get the idea.
</p>


<verbatim>
[root@lax]ipv4 > diff -c af_inet.c*
*** af_inet.c Wed Feb 23 23:31:35 2005
--- af_inet.c~ Thu Feb 17 18:13:13 2005
***************
*** 423,434 ****

        snum = ntohs(addr->sin_port);
        err = -EACCES;
- #if 0
- /* removed by klacke */
        if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
                goto out;
- #endif
-

        /* We keep a pair of addresses. rcv_saddr is the one
         * used by hash lookups, and saddr is used for transmit.
--- 423,430 ----
</verbatim>





<erl>
out(A) -> {ssi, "END2",[],[]}.
</erl>
Something went wrong with that request. Please try again.