Creating your own cvsupd server

With the upcoming work I’m going to be doing on FreshPorts, I thought it best to start up a cvsup server
for the source code. This server will be used to share the data amongst the other
FreshPorts developers. This article starts that process.

I first wrote about cvsupd
on 6 August 1999. That article is still around, but now
that I’m installing a cvsupd server for my own needs, instead of creating a mirror, I found my existing notes a bit lacking.
Hence, this article.

I used John Polstra’s CVSUP
FAQ for this exercise. Of note is the section on setting up a test server.
It’s what I used as the basis for this article.

The install

NOTE: in more recent versions of FreeBSD, cvsupd can be found in net/cvsup-without-gui.
Yet cvsupd is started by /usr/local/etc/rc.d/cvsupd which is installed by net/cvsup-mirror
cvsupd_enable=”YES” in /etc/rc.conf
cvsupd_flags=”-c sup:/home/repositories/sup”
Turn off your old cvsupd to avoid accidents.

Setting up a test server

In this section, I’m going to show you the bare minimum required to get
the server running so you can talk to it from a client.

This is the main directory which cvsupd uses and its where the repositories
will reside. In this example, we’ll use /usr/local/etc/cvsup (which is
the default base directory for cvsupd). See the -b option.

The releases file identifies the releases which are associated with this
collection.
Create /usr/local/etc/cvsupd/sup/test/releases to contain the following:

cvs list=list.cvs prefix=/home/repositories

This defines the prefix. Our repository will exist at /home/repositories

Create the list.cvs file:

This file contains the rules for use when processing the cvs release. In this
case, it contains the freshports-db collection. Here’s what’s in that
file:

upgrade freshports-db
This file should be in the directory /usr/local/etc/cvsupd/sup/test/.

This is your repository and it is relative to the prefix supplied in the releases
file. In our example, the repository will exist at /home/repositories/freshports-db.
It is the contents of this subtree which will be transferred.

Start the server

Here’s where we start the server with a very simple situation:

/usr/local/sbin/cvsupd

We have not specified a base directory. cvsupd will use the default
directory, which we also used to create our base directory. We
have not specified the -e option, which means cvsupd will run from the command
line and not go into the background. Here is what it looks like when cvsupd
starts:

This method is fine for testing, but I actually run cvsupd as the nobody and
ensure that everything it serves is readable by everyone. cvsupd does not
create or write files, so from a security point of view, the risk of cvsupd being
tricked into damaging your system is actually quite low.

I start cvsupd automatically at system startup by creating /usr/local/etc/rc.d/cvsupd.sh,
which is chmod 770:

Setting up a test client

We will now set up the test client to use our test server. We are
doing this on the same box as cvsupd is running. Create the directory ~/cvs-test.
In this directory, create supfile and place the following
in it:

This is our cvsup configuration file. We have specified that we will be
connecting to the cvsup server on localhost (i.e. this box) and that we
will be obtaining the cvs release. From that release, we want the test
collection.

To run cvsup on the client and pull down the collection, issue the following command:

In this example, I’m going to add a very simple collection, test2,
which contains only contrib/top.
This isn’t really a practical example, but it might help to illustrate how the
various components of cvsup fit together.

I’ll create the collection directory:

mkdir /usr/local/etc/cvsup/sup/test2

In that directory, I’ll specify the releases associated with this collection by
creating releases which contains the following (all on one line):

cvs list=list.cvs prefix=/home/repositories/FreeBSD/ncvs/src/contrib/

This indicates that the repository actually exists at /home/repositories/FreeBSD/ncvs/src/contrib/.

Then I create the list.cvs file, the same directory as releases, to
contain this:

upgrade test2

I can use the same supfile as in the previous example, but I change test
to top.

Putting things in a different place

The supfile example contains a base specifiation of base=.
which puts everything from cvsup into the current directory. That’s not the ideal
situation, but it’s what we used for our testing. Now let’s change that. Let’s
put everything into /home/dan/mysupfiles. The first step is to modify
our supfile from the previous examples and change base to look like this:

This section will concentrate on restricting access to your cvsup server
by authenticating the connections. Authentication is controlled by the existence of
the file cvsupd.access which must appear in the base directory (in the example
above, the base directory is /usr/local/etc/cvsup). If this file does not
exist, no authentication takes place.

The file cvsupd.passwd (again, in the
base directory) contains the authentication rules. Here’s the contents I was testing
with:

Send this line to the server administrator at cvsup.example.org:
----------------------------------------------------------------
dan@develop.example.org:$md5$c2e5a85c8042ce9f8c71bcc0f52876c8::
----------------------------------------------------------------
Be sure to send it using a secure channel!

Add this line to your file "$HOME/.cvsup/auth", replacing "XXX"
with the password you typed in:
----------------------------------------------------------------
cvsup.example.org:dan@develop.example.org:XXX:
----------------------------------------------------------------
Make sure the file is readable and writable only by you!

The password I entered was "secret". So this is what I placed in ~/.cvsup/auth
on my client machine:

cvsup.example.org:dan@develop.example.org:secret:

That should be enough to authenticate everyone.

Access Control

Perhaps you don’t want everyone accessing your cvsup server. I know I don’t. So I’ve added some
rules to my packet filter to restrict access. People scanning the box can’t
even tell there is a cvsup server there. But multiple layers of protection can be a good thing. That’s
why I added more. If you read the man page for cvsupd, you’ll see that that cvsupd.access
is your friend. I added a few rules to this file, which normally resides under
/usr/local/etc/cvsup, which permitted certain trusted host unlimited access to my server.

#
# allow anything from our local network

+10.0.0.0/24

# allow connections from local host
+127.0.0.1/32

# everything else must authenticate
*0.0.0.0/0

Using the above scenario, I didn’t have to do anything special for boxes on my 10.0.0.* network
and the cvsup server could access itself. Everyone else, including my remote boxes, must
authenticate using the methods described in the previous section.

Secrecy

From man cvsupd:

If secrecy is desired then the connection can be tunneled
through ssh.

I tried to get this to work, but I failed. If anyone has a practical example,
please add it to the comments section. Thanks.

Common problems and solutions

…it means the information contained in the releases file is
incorrect. In my case, I had put my data at /usr/repositories instead of /home/repositories
as specified in releases. Once I moved repositories to /home,
all was well.

One Response to “Creating your own cvsupd server”

That connect to box.example.com, and forward your local
port 5559 to box.example.com, and thence to cvs.example.com,
port 5999.

This will help you in two situations:

1) You have a shell account at example, but their cvs
server is firewalled. As long as box.example.com is
on the cvs server’s subnet, then this forward will
let you point cvsup at localhost for the loot.

2) You are *inside* a firewall, and can’t get out except
for ssh. Then, the same forward will let you tunnel 5999
through 22 on the firewall, to the remote host.

Now, anyone who ssh’s to port 2048 on box2, will be tunneled
through non-priveledged ports on box2 -> box1, and thence to
22 on your box. You can use this to get ssh access in (indeed,
any access – irc server on your desktop at work? no problem 😉
through even the most severe firewall.