Monday, March 10, 2008
Libpq vs Libpqxx
After using Libpqxx for the past 5 years on a PostgreSQL 7.4 database, I migrated the database to 8.3 and Libpqxx to the current stable version - 2.6.9. I am running dual quad-core Xeon processors on a 64-bit Red Hat Enterprise 5 Server with GCC 4.1.x. Libpqxx is just a wrapper library around Libpq. There are performance issues because Libpq can be called directly without incurring object / template overhead. After deciding to migrate our codebase to use Libpq, I was very pleased with the results. Error checking is simple, code execution is faster, and library / executable sizes were reduced.
Sunday, December 2, 2007
RESTful Web Services
After writing a simple Ruby interface into Flickr this weekend, I began to question why Flickr wrote their API the way that they did. Having some level of familiarity with Rails scaffolds and CRUD actions and having somewhat kept up with the state of web services development, I swung by the bookstore and picked up a copy of RESTful Web Services, by Leonard Richardson & Sam Ruby.
This is an exceptional book. I highly recommend this book to anyone who is doing anything technical with the Web.
For a detailed discussion of Representational State Transfer, see Roy Fielding's PhD dissertation, "Architectural Styles and the Design of Network-based Software Architectures". Roy Fielding is co-founder of the Apache project and worked on the original http protocol.
Thursday, November 22, 2007
Ruby on Rails and Lighttpd(SSL) Installation
Ruby on Rails and Lighttpd(SSL) Installation
I. Check the system
Before installing, let's check that our system has the necessary tools so that the installation process can proceed smoothly. The system we'll be setting up should be similar to my own.$ echo $SHELL /bin/bash $ uname -a Linux dash.bryanhinton.com 2.6.18-8.1.10.el5 #1 SMP Thu Aug 30 20:43:15 EDT 2007 \ i686 i686 i386 GNU/Linux $ echo $PATH /usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/bin:/bin: \ /usr/bin:/home/bryan/bin:/usr/local/bin:/usr/sbin $ echo $LD_LIBRARY_PATH /usr/local/lib:/usr/lib:/lib $ make -v GNU Make 3.81 $ autoconf -V autoconf (GNU Autoconf) 2.59 $ gcc -v Using built-in specs. Target: i386-redhat-linux Configured with: ../configure --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info \ --enable-shared --enable-threads=posix --enable-checking=release --with-system-zlib \ --enable-__cxa_atexit --disable-libunwind-exceptions \ --enable-libgcj-multifile --enable-languages=c,c++,objc,obj-c++,java,fortran,ada \ --enable-java-awt=gtk --disable-dssi --enable-plugin \ --with-java-home=/usr/lib/jvm/java-1.4.2-gcj-1.4.2.0/jre \ --with-cpu=generic --host=i386-redhat-linux Thread model: posix gcc version 4.1.1 20070105 (Red Hat 4.1.1-52)
II. Check the host configuration on the network
Change the hostname.
$ su ******* # hostname WCLI404892341 # hostname dash.bryanhinton.com # hostname dash.bryanhinton.com
Now Open /etc/sysconfig/network and /etc/hosts and make sure that they look like the following:
# cat /etc/sysconfig/network NETWORKING=yes NETWORKING_IPV6=yes HOSTNAME=dash.bryanhinton.com # cat /etc/hosts 127.0.0.1 localhost.localdomain localhost 74.53.242.146 dash.bryanhinton.com dash ::1 localhost6.localdomain6 localhost6
III. Install Ruby 1.8.6 patchlevel 110, RubyGems 0.9.5, and Ruby FastCGI Bindings
As of November 24, 2007, 1.8.6-p110 is the recommended, stable version and 0.9.5 is the recommended, stable version of RubyGems. RubyGems is the Ruby package management system and a gem is a packaged Ruby application or library.
# exit $ mkdir $HOME/src $ cd $HOME/src $ wget http://ftp.ruby-lang.org/pub/ruby/1.8/ruby-1.8.6.tar.gz $ tar -xzvf ruby-1.8.6.tar $ cd ruby-1.8.6 $ ./configure $ make $ su ******* # make install # exit $ which ruby /usr/local/bin/ruby $ ruby -v ruby 1.8.6 (2007-09-23 patchlevel 110) [i686-linux] $ cd $HOME/src $ wget http://rubyforge.org/frs/download.php/28174/rubygems-0.9.5.tgz $ tar -xzvf rubygems-0.9.5.tgz $ cd rubygems-0.9.5 $ su ****** # ruby setup.rb # exit # gem -v 0.9.5 # gem install fcgi
IV. Install Rails
# gem install rails --include-dependencies
V. Install Lighttpd with SSL
# openssl version OpenSSL 0.9.8b 04 May 2006 # exit $ cd $HOME/src $ wget http://www.lighttpd.net/download/lighttpd-1.4.18.tar.gz $ tar -xzvf lighttpd-1.4.18.tar.gz $ cd lighttpd-1.4.18 $ ./configure --with-openssl --with-openssl-libs=/usr/lib/openssl ... ... ... Plugins: enabled: mod_access mod_accesslog mod_alias mod_auth mod_cgi mod_compress mod_dirlisting mod_evhost mod_expire mod_extforward mod_fastcgi mod_flv_streaming mod_indexfiles mod_proxy mod_redirect mod_rewrite mod_rrdtool mod_scgi mod_secdownload mod_setenv mod_simple_vhost mod_ssi mod_staticfile mod_status mod_trigger_b4_dl mod_userdir mod_usertrack mod_webdav disabled: mod_cml mod_magnet mod_mysql_vhost Features: enabled: auth-crypt compress-bzip2 compress-deflate compress-gzip large-files network-ipv6 network-openssl regex-conditionals disabled: auth-ldap stat-cache-fam storage-gdbm storage-memcache webdav-locks webdav-properties $ make $ su ****** # make install # mkdir /etc/lighttpd/ # cp doc/lighttpd.conf /etc/lighttpd/ # cp doc/rc.lighttpd /etc/init.d/lighttpd # chmod +x /etc/init.d/lighttpd # mkdir /var/www # mkdir /var/www/html # groupadd lighttpd # useradd -g lighttpd -d /var/www -s /bin/false lighttpd # chown -R lighttpd.lighttpd /var/www # chown -R lighttpd.lighttpd /var/log/lighttpd
Now let's Configure Lighttpd. As stated earlier, there is a public IP address bound to the network card. We are going to bind the lighttpd daemon to the public IP address on port 80 and port 443. This assumes that a correctly configured SSL certificate. The following lines in /etc/init.d/lighttpd.conf should look like the following:
server.username = "lighttpd" server.groupname = "lighttpd" accesslog.filename = "/var/log/lighttpd/access.log" $HTTP["host"] =~ "bryanhinton\.com$" { server.document-root = "/var/www/html/bryanhinton/public/" accesslog.filename = "/var/www/html/bryanhinton/log/access.log" server.indexfiles = ( "dispatch.fcgi", "index.html" ) server.error-handler-404 = "/dispatch.fcgi" # rails stuff #### fastcgi module fastcgi.server = ( ".fcgi" => ( "test" => ( "socket" => "/tmp/test1.socket", "bin-path" => "/var/www/html/bryanhinton/public/dispatch.fcgi", "min-procs" => 1, "max_procs" => 2 ) ) ) } $SERVER["socket"] == "74.53.242.146:443" { ssl.engine = "enable" ssl.pemfile = "/etc/lighttpd/ssl/bryanhinton.com/bryanhinton.pem" server.name = "bryanhinton.com" server.document-root = "/var/www/html/bryanhinton/public/" }
VI. Start Lighttpd
# /etc/init.d/lighttpd start
VII. Configure a Rails Application
First, let's make sure our standard login ID is associated with the lighttpd group. Open /etc/groups and make sure that there is a line that looks like the following:
lighttpd:x:521:lighttpd,LOGIN_ID
Configure a Rails Application
$ cd /var/www/html $ rails bryanhinton $ cd bryanhinton $ ruby script/generate controller Content $ rm public/index.html
edit config/routes.rb
# add this to line 21 map.connect ':action', :controller => 'Content' # original line 24 #map.connect '', :controller => "welcome" # change to this on line 24 map.connect '', :controller => 'Content'
Setup smtp to send e-mail from Rails. Modify config/environments/development.rb so that it looks like the following:
config.action_mailer.raise_delivery_errors = false config.action_mailer.delivery_method = :smtp config.action_mailer.perform_deliveries = true config.action_mailer.raise_delivery_errors = true config.action_mailer.smtp_settings = { :address => "smtphost.bryanhinton.com" :port => 25, :domain => "bryanhinton.com" :authentication => :log :user_name => "INSERT USERNAME HERE" :password => "INSERT PASSWORD HERE" }
IIX. Create a development database in MySQL and then Configure in Rails
$ mysqladmin -u myusername create bryanhinton_development -p $ gem install mysql
Edit config/database.yml and ensure that it looks similar to the following. We are only setting up a development database
development: adapter: mysql database: bryanhinton_development username: MY_MYSQL_USER_NAME password: MY_MYSQL_PASSWORD socket: /var/lib/mysql/mysql.sock
IX. Test the database connection
$ cd /var/www/html/bryanhinton $ rake db:migrate
X. Create site layout
$ cd /var/www/html/bryanhinton/app/views/layouts
Place the following lines in application.rhtml
<html> <body> <%= render :partial => "layouts/header" %> <%= render :partial => "layouts/leftnav" %> <%= render :partial => "layouts/rightnav" %> <%= yield :layout %> <%= render :partial => "layouts/footer" %> </body> </html>
Create the files that application.rhtml references
$ echo "My Header" > _header.rhtml $ echo "Left Menu" > _leftnav.rhtml $ echo "Right Col News" > _rightnav.rhtml $ echo "My Footer" > _footer.rhtml
XI. Create an index method in the Content controller
Place the following lines in /var/www/html/bryanhinton/app/controllers/content_controller.rb
class ContentController < ApplicationController def index end
XII. Create a view for the index method
Create a view for the index method called index.rhtml in /var/www/html/bryanhinton/app/views/content
$ cd /var/www/html/bryanhinton/app/views/content $ echo "Hello World!" > index.rhtml
XIII. Test the installation!
Open up a web browser and go to the site URL i.e. http://bryanhinton.com OR http://bryanhinton.com/index
Wednesday, January 3, 2001
OpenBSD bridge without IPs using IPF Tutorial
Overview
With OpenBSD and IP Filter, a bridge can be setup that filters incoming traffic. The bridge is not assigned an IP address on either network card. The benefit of this type of firewall is that the sender of an incoming packet is entirely oblivious to the existence of an intermediate bridge. This provides transparency and allows the firewall, which is maintained on the bridge, to securely filter incoming packets and forward them without modification to the internal destination. This guide walks through two typical home network connection setups (ADSL and cable modem) using OpenBSD 2.8.
A bridge is a software or hardware device used to connect two network segments. Unlike a router, it creates the appearance of a single, large network segment. The bridge used in this example will be transparent. It will not allow any connections to be made to its internal services and it will still function as a secure firewall and stateful packet filter.
These examples are "real world" examples of two typical network environments.
Example 1 - An ADSL line connected via a hardware router, with all LAN workstations using static IPs and running services.
Example 2 - A cable modem Internet connection with all LAN workstations reaching the Internet through a single, separate router computer. Nat cannot be run on the bridge because the bridge does not have ip addresses assigned to it's interfaces. No services will be run on the LAN workstations.
Setup Overview
The first step is to setup configuration files so that the bridge will be activated upon reboot. These files must be configured for the bridge to properly function:
Edit /etc/hostname.*
/etc/hostname. must be setup for each network card. These files are used when the system boots. If these files exist, the initialization scripts take the information contained in these files and configure the devices.
Use 'dmesg' as a guide to what network card driver is being used.Edit /etc/bridgename.bridge0
/etc/bridgename.bridge0 needs to be created so that the bridge will be brought up during system initialization.
Edit /etc/ipf.rules
/etc/ipf.rules must be created for the packet filtering rules to take place.
Edit /etc/rc.conf
/etc/rc.conf must be edited to turn on IPF (IP Filter).
rc.conf must have "ipfilter=YES"
Example 1: ADSL line with services on static IPs
Network topology:
adsl <--> hw router with 4 ports <--> /fxp0 bridge /fxp1 <--> 5port 3 com hub <---> Internal LAN computers
The Internet connection, an ADSL line, enters the hardware router. An rj45 cable connects the hardware router and the bridge. This connects to interface fxp0 on the bridge. The bridge's second network card, fxp1, connects to the 5 port hub through another rj45 cable. Using static ip addresses, the LAN workstations connect, through the hub, to the internet.
- Hardware Used:
Hardware router
Bridge computer
Workstation running OpenBSD 2.8
Intel pro/100 network card with device name: fxp0
Intel pro/100 network card with device name: fxp15 port 3com home connect hub
Enough RJ-45 cable for the network
fxp0 is the external network interface and is connected to the Internet through the hardware ADSL router.
fxp1 is the internal network interface and is connected to the LAN hub.
Changes to /etc/rc.conf
ipfilter=YES # IPF must be enabled for the bridge to work
inetd=NO # Services will not be run on this box
portmap=NO # No reason to have this enabled
Create /etc/hostname.fxp0
inet media 10BaseT # Adjust this to the proper media type
up # See ifconfig(8) for more details
Create /etc/hostname.fxp1
inet media 10BaseT # Also adjust to proper network media type
up
Create /etc/bridgename.bridge0
add fxp0 add fxp1 up
Create /etc/ipf.rules
#------------------------------------------------------------------
# fxp0 - External interface - internet
# fxp1 - Internal interface - protected
# lo0 - loopback interface - localhost only
# Netmask = 255.255.255.248 = /29
# 1.1.1.9 Web Server, Primary DNS, Mail Server
# 1.1.1.8 Secondary DNS
# 1.1.1.7 Workstation
#
# Allow all incoming and outgoing packets on the internal loopback interface
#pass in quick on lo0 all
pass out quick on lo0 all#
# drop any IP packets with options set
# ipopts include lsrr and ssrr
# IPF example ipopts
#block in quick all with ipopts#
# Drop any packets that are too short to compare
# IPF examples short
#block in quick all with short#
# Block any incoming IP fragments
# IPF examplesblock in quick all with frag
pass in quick on fxp1 proto tcp/udp all keep state
pass in quick on fxp1 proto icmp all keep state#
# Don't allow any other incoming traffic to the internal network card.
#block in quick on fxp1 all#
# Block nmap OS fingerprinting attempts
# From the OpenBSD FAQ.
#block in quick on fxp0 proto tcp all flags FUP#
# Block incoming traffic from the unroutable address blocks
#
# See http://www.3com.com/nsc/501302.html for more info on unroutables.
#
# Note: 'out' cannot be used with any of these bridge rules. Therefore,
# block in on the other interface. It will probably stay that
# way as it's harder to allow 'out' rules.
#
# Blocking in on fxp0 will keep inappropriate IPs off of the external interface.
# Blocking in on fxp1 will keep inappropriate packets from coming out
# of the internal network.
#block in quick on fxp0 from 255.255.255.255/32 to any
block in quick on fxp0 from 192.168.0.0/16 to any
block in quick on fxp0 from 172.16.0.0/12 to any
block in quick on fxp0 from 127.0.0.0/8 to any
block in quick on fxp0 from 10.0.0.0/8 to any
block in quick on fxp0 from 0.0.0.0/32 to any#
# Prevent smurf attack
# To prevent this, incoming traffic in the broadcast address range needs to be
# blocked.
# Directed broadcasts are off by default OpenBSD FAQ 6.6
#block in log quick on fxp0 from any to 1.1.1.0/29
block in log quick on fxp0 from any to 1.1.1.255/29#
# Protect real IP addresses behind the firewall
#block in log quick on fxp0 from 1.1.1.7 to any
block in log quick on fxp0 from 1.1.1.8 to any
block in log quick on fxp0 from 1.1.1.9 to any#
# Pass in and keep state on certain types of ICMP messages.
# Allow ICMP messages that are non-volatile and needed because of added
# functionality:
# icmp-type 0 : echo reply (ping reply) RFC 792
# icmp-type 3 : Destination Unreachable RFC 792
# icmp-type 8 : echo request (ping request) RFC 792
# icmp-type 11: time exceeded (traceroute) RFC 792
# Larger list of ICMP type numbers
#pass in quick on fxp0 proto icmp from any to 1.1.1.9/29 icmp-type 0 keep state
pass in quick on fxp0 proto icmp from any to 1.1.1.9/29 icmp-type 3 keep state
pass in quick on fxp0 proto icmp from any to 1.1.1.9/29 icmp-type 8 keep state
pass in quick on fxp0 proto icmp from any to 1.1.1.9/29 icmp-type 11 keep state#
# DNS generally uses TCP under two circumstances.
# 1. Zone transfers between primary and secondary name servers.
# 2. When a client make a query (udp) and the response exceeds 512 bytes, the query is re-issued using tcp.
# Thus, allow TCP on port 53 but keep state and check for the Syn flag (tcp).
#
# See section 2.7 (page 11) and 3.3 (page 25) of RFC 793
# and IPF example tcpflags for more information on 'flags S'.
#pass in quick on fxp0 proto tcp from any to 1.1.1.8 port = 53 flags S keep state
pass in quick on fxp0 proto tcp from any to 1.1.1.9 port = 53 flags S keep state#
# Allow people to query my nameservers but keep state (udp) on the connection
# See RFC 1034 section 4.3.5 for more information on DNS.
#
pass in quick on fxp0 proto udp from any to 1.1.1.8 port = 53 keep state
pass in quick on fxp0 proto udp from any to 1.1.1.9 port = 53 keep state
#
# Mail (SMTP) - allow packets with only syn flag set (initial connection) and
# keep state on connection.
# See section 2.7 (page 11) and 3.3 (page 25) of RFC 793
# and IPF example tcpflags for more information.
#pass in quick on fxp0 proto tcp from any to 1.1.1.9 port = 25 flags S keep state#
# Webserver - allow packets with only syn flag set (set during initial
# connection) and keep state on connection.
# See section 2.7 (page 11) and 3.3 (page 25) of RFC 793
# and IPF example tcpflags for more information.
#pass in quick on fxp0 proto tcp from any to any port = 80 flags S keep state#
# Block any other incoming traffic
#block in quick on fxp0
Example 2: Cable modem with software router running NAT and no services
Internet --- cable modem ----- /ep0 bridge /ep1 --- /xl0 software router /xl1 ----- 8 port hub --- Internal LAN computers
The cable modem is the connection to the outside network, the Internet. The cable modem is connected to the first network card, xl0, on the bridge. From there, packets are checked using IPF and, if they pass, they are sent to the second network card, xl1, and used by the internal network. The xl1 interface is connected to the first network card on the OpenBSD software router using RJ-45 cable. From here the traffic is again analyzed but, this time, by IP Network Address Translation (IPNAT). Subsequently, IPNAT forwards the packets to the correct host in the internal network. From the second network card, ep1, the packets which pass are sent to the 8 port hub. Here, the packets are broadcast to all of the LAN computers.
- Hardware Used:
cable modem
Bridge computer
OpenBSD workstation running 2.8
3com 3c905b-TX network card with device name: ep0
3com 3c905b-TX network card with device name: ep1Router computer running NAT
OpenBSD workstation running 2.8
3com 3c509 network card with device name: xl0
3com 3c509 network card with device name: xl18 port hub.
Enough RJ-45 cable for the network.
RJ-45 crossover cable for going between the bridge and router.
ep0 is the network card connected to the cable modem
ep1 is the network card connected to the internal network.
Changes to /etc/rc.conf
ipfilter=YES # enable IPF for the bridge to work
inetd=NO # services cannot be run on this box anyway
portmap=NO # No reason to have this enabled
Create /etc/hostname.ep0
media 10BaseT up
Create /etc/hostname.ep1
media 10BaseT up
Create /etc/bridgename.bridge0
add ep0
add ep1
up
Create /etc/ipf.rules
#-----------------------------------
# ep0 - Network card connected to the cable modem through rj-45
# ep1 - Network card connected to the Internal router - protected
# lo0 - loopback, localhost only
#
# Allow the loopback device to bypass the rules since it is localhost.
#pass in quick on lo0 all#
# drop any packets with IP options set
# IPopts include lsrr and ssrr
# IPF example ipopts
#block in quick all with ipopts#
# Drop any packets that are too short to compare
# A short packet doesn't contain a complete IP header
# IPF example short
#block in quick all with short#
# Block any incoming IP fragments
# A frag is a fragment of an IP datagram
# IPF example frag
#block in quick all with frag#
# Block nmap OS fingerprinting attempts
# From the OpenBSD FAQ.
#block in quick proto tcp all flags FUP#
# Pass in packets from DHCP server
# May not be needed in all cases if the dhcp lease lasts a long time.
# This assumes that the ISP's DHCP server is 24.168.0.1; change it accordingly.
# If unknown, dhcp client will use 0.0.0.0/32 with a broadcast
# address of 255.255.255.255/32 so change this line.
#pass in quick on ep0 proto udp from 24.168.0.1/32 port = 67 to any port = 68 keep state#
# Block incoming traffic from the unroutable address blocks
# See http://www.3com.com/nsc/501302.html for more info on unroutable
#block in quick on ep0 from 192.168.0.0/16 to any
block in quick on ep0 from 172.16.0.0/12 to any
block in quick on ep0 from 127.0.0.0/8 to any
block in quick on ep0 from 10.0.0.0/8 to any#
# add in blocks on ep1 from LAN IPs other than the class being
# used. Try to keep it as generic as possible.
#
#
# Allow packets out and keep state on them. This allows use of
# the connection as if there was no firewall, but outside users
# cannot connect to. If the packets passed the rules above (were not
# matched) then these packets will be allowed to leave the internal
# network and proceed on to the Internet by these two rules.
#
# See section 2.7 (page 11) and 3.3 (page 25) of RFC 793
# and IPF example tcpflags for more information on 'flags S'.
#pass in quick on ep1 proto tcp from any to any flags S keep state
pass in quick on ep1 proto udp from any to any keep state
pass in quick on ep1 proto icmp from any to any keep state#
# Do not allow any traffic coming in that has not not initiated first
# since there are not any servers running. The keep state rules for ep1
# above will let the packets out. And this rule doesn't allow anyone
# to contact the computer.
#block in quick all
Manually initialize interfaces
Rather than rebooting the computer to clear and re-initialize the network interfaces, the following commands may be executed with super-user privelages if ipf has already been activated in the kernel.
root@localhost# ifconfig fxp0 delete
root@localhost# ifconfig fxp1 delete
root@localhost# brconfig bridge0 add fxp0 add fxp1 up
If the bridge0 interface was up from another configuration, flush the interface cache and delete all existing interfaces from bridge0.
root@localhost# brconfig bridge0 flushall
root@localhost# brconfig bridge delete fxp0
root@localhost# brconfig bridge delete fxp1
root@localhost# brconfig bridge0 add fxp0 add fxp1 up
Make sure all of the interfaces are up and configured correctly. The network interface parameters should look like the following. Run the following commands to verify.
root@localhost# ifconfig fxp0
fxp0: flags=8943 mtu 1500
media: Ethernet autoselect (10BaseT)
status: active
root@localhost# ifconfig fxp1
fxp1: flags=8943 mtu 1500
media: Ethernet autoselect (10BaseT)
status: active
root@localhost# ifconfig bridge0
bridge0: flags=41 mtu 1500
In addition, run the following command to verify bridge0's configuration.
Note: xx:xx:xx:xx:xx:xx is some arbitrary hex address.
root@localhost# brconfig bridge0
bridge0: flags=41
Interfaces:
fxp1 flags=3
fxp0 flags=3
Addresses( max cache: 100, timeout: 240):
xx:xx:xx:xx:xx:xx fxp1 1 flags=0<>
xx:xx:xx:xx:xx:xx fxp0 1 flags=0<>
xx:xx:xx:xx:xx:xx fxp0 1 flags=0<>
Initialize IPF
Run the following command to initialize the ruleset if not rebooting.
root@localhost# ipf -Fa -FS -vf /etc/ipf.rules -E
Configure LAN Workstations
The firewall/bridge is now transparent. Individual LAN workstations and or servers may be configured using the route command. For example, if the isp assigned the gateway address: 1.1.1.10, the following could be used to set up the route on an individual workstation.
root@localhost# route add default 1.1.1.10
References
OpenBSD FAQ on IP Filter
IP Filter website
IP Filter examples
IP Filter mailing list
IP Filter howto html text postscript Adobe Acrobat
IPF Stateful filtering postscript
Building Linux and OpenBSD Firewalls, Wes SonnenReich, Tom Yates (John Wiley & Sons, 2000)
TCP/IP Illustrated, Volume 1: The Protocols, W. Richard Stevens (Prentice Hall, 1994)
Practical Internetworking with TCP/IP and UNIX, Smoot Carl-Mitchell, John S. Quarterman (Addison-Wesley, 1993)
About us
Bryan Hinton is an undergraduate student at the University of Texas at Dallas majoring in computer science. He is concurrently working on his undergraduate and graduate degrees in Computer Science.
Doug Hogan is an undergraduate student at the University of Cincinnati majoring in computer science. He is the vice-president of the UC Free Operating Systems group. Doug is a member of the OpenBSD development team.