From: Ben Pfaff Date: Fri, 13 Jun 2008 20:36:00 +0000 (-0700) Subject: Implement Debian-based packaging and deployment infrastructure. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=62fd5fc4479700b595566c4907cfb8d34ba549e9;p=openvswitch Implement Debian-based packaging and deployment infrastructure. --- diff --git a/configure.ac b/configure.ac index 0cdc593a..2be62d59 100644 --- a/configure.ac +++ b/configure.ac @@ -6,6 +6,12 @@ AC_PROG_CC AC_PROG_CPP AC_PROG_LD +AC_ARG_VAR([PERL], [path to Perl interpreter]) +AC_PATH_PROG([PERL], perl, no) +if test "$PERL" = no; then + AC_MSG_ERROR([Perl interpreter not found in $PATH or $PERL.]) +fi + AC_USE_SYSTEM_EXTENSIONS AC_PROG_LIBTOOL diff --git a/debian/.gitignore b/debian/.gitignore new file mode 100644 index 00000000..b3189e7d --- /dev/null +++ b/debian/.gitignore @@ -0,0 +1,9 @@ +*.debhelper +/files +/openflow +/openflow-common +/openflow-controller +/openflow-pki +/openflow-switch +/openflow-datapath-source +*.substvars diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 00000000..ad26b6cd --- /dev/null +++ b/debian/changelog @@ -0,0 +1,5 @@ +openflow (0.8.1) unstable; urgency=low + + * Development version. + + -- OpenFlow team Mon, 19 Nov 2007 14:57:52 -0800 diff --git a/debian/compat b/debian/compat new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 00000000..ce55e8ea --- /dev/null +++ b/debian/control @@ -0,0 +1,57 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10, libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2 +Standards-Version: 3.7.3 + +Package: openflow-datapath-source +Architecture: all +Depends: module-assistant, bzip2, debhelper (>= 5.0.37) +Suggests: openflow-switch +Description: Source code for OpenFlow datapath Linux module + This package provides the OpenFlow datapath module source code that + is needed by the kernel-based OpenFlow switch. The kernel module can + be built from it using module-assistant or make-kpkg. README.Debian + in this package provides further instructions. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-common +Architecture: any +Depends: ${shlibs:Depends} +Description: OpenFlow common components + openflow-common provides components required by both openflow-switch + and openflow-controller. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-switch +Architecture: any +Suggests: openflow-datapath-module +Depends: ${shlibs:Depends}, ${misc:Depends}, openflow-common, libwww-perl, libdigest-sha1-perl, dhcp3-client +Description: OpenFlow switch implementations + openflow-switch provides the userspace components and utilities for + the OpenFlow kernel-based switch. It also includes a userspace-only + implementation of an OpenFlow switch. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-pki +Architecture: all +Depends: ${shlibs:Depends}, ${misc:Depends}, ${perl:Depends}, apache2 +Description: OpenFlow public key infrastructure + openflow-pki provides PKI (public key infrastructure) support for + OpenFlow switches and controllers, reducing the risk of + man-in-the-middle attacks on the OpenFlow network infrastructure. + . + OpenFlow is a protocol for flow-based control over network switching. + +Package: openflow-controller +Architecture: any +Depends: ${shlibs:Depends}, openflow-common, openflow-pki +Description: OpenFlow controller implementation + The OpenFlow controller enables OpenFlow switches that connect to it + to act as MAC-learning Ethernet switches. + . + OpenFlow is a protocol for flow-based control over network switching. diff --git a/debian/control.modules.in b/debian/control.modules.in new file mode 100644 index 00000000..cc149cac --- /dev/null +++ b/debian/control.modules.in @@ -0,0 +1,19 @@ +Source: openflow +Section: net +Priority: extra +Maintainer: OpenFlow Team +Build-Depends: debhelper (>= 5.0.37) +Standards-Version: 3.7.3 + +Package: openflow-datapath-module-_KVERS_ +Architecture: any +Recommends: kernel-image-_KVERS_, openflow-switch +Provides: openflow-datapath-module +Description: OpenFlow Linux datapath kernel module + This package contains the OpenFlow loadable datapath kernel modules for + the kernel-image-_KVERS_ package. + . + If you compiled a custom kernel, you will most likely need to compile + a custom version of this module as well. The openflow-datapath-source + package has been provided for this purpose. Refer to README.Debian + provided in that package for further instructions. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 00000000..b369ec39 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,38 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + We are making the OpenFlow specification and associated documentation + (Software) available for public use and benefit with the expectation + that others will use, modify and enhance the Software and contribute + those enhancements back to the community. However, since we would like + to make the Software available for broadest use, with as few + restrictions as possible permission is hereby granted, free of charge, + to any person obtaining a copy of this Software to deal in the Software + under the copyrights without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + The name and trademarks of copyright holder(s) may NOT be used in + advertising or publicity pertaining to the Software or any derivatives + without specific, written prior permission. + diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 00000000..ca882bbb --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/debian/ofp-switch-setup b/debian/ofp-switch-setup new file mode 100755 index 00000000..0c03c332 --- /dev/null +++ b/debian/ofp-switch-setup @@ -0,0 +1,487 @@ +#! /usr/bin/perl + +use POSIX; +use Debconf::Client::ConfModule ':all'; +use HTTP::Request; +use LWP::UserAgent; +use Digest::SHA1 'sha1_hex'; +use strict; +use warnings; + +my $debconf_owner = 'openflow-switch'; + +my $default = '/etc/default/openflow-switch'; +my $etc = '/etc/openflow-switch'; +my $privkey_file = "$etc/of0-privkey.pem"; +my $req_file = "$etc/of0-req.pem"; +my $cert_file = "$etc/of0-cert.pem"; +my $cacert_file = "$etc/cacert.pem"; + +my $ua = LWP::UserAgent->new; +$ua->timeout(10); +$ua->env_proxy; + +version('2.0'); +capb('backup'); +title('OpenFlow Switch Setup'); + +my (%netdevs) = find_netdevs(); +db_subst('netdevs', 'choices', + join(', ', map($netdevs{$_}, sort(keys(%netdevs))))); +db_set('netdevs', join(', ', grep(!/IP/, values(%netdevs)))); + +if (-e $default) { + my (%config) = load_config($default); + + my (%map) = + (NETDEVS => sub { + db_set('netdevs', join(', ', map($netdevs{$_}, + grep(exists $netdevs{$_}, split)))) + }, + IN_BAND => sub { + db_set('band', $_ eq 'no' ? 'in-band' : 'out-of-band') + }, + SWITCH_IP => sub { db_set('switch-ip', $_) }, + CONTROLLER => sub { db_set('controller-vconn', $_) }, + PRIVKEY => sub { $privkey_file = $_ }, + CERT => sub { $cert_file = $_ }, + CACERT => sub { $cacert_file = $_ }, + ); + + for my $key (keys(%map)) { + local $_ = $config{$key}; + &{$map{$key}}() if defined && !/^\s*$/; + } +} + +my $cacert_preverified = -e $cacert_file; + +if (! -e $privkey_file) { + my $old_umask = umask(077); + run_cmd("ofp-pki req $etc/of0 >&2 2>/dev/null"); + chmod(0644, $req_file) or die "$req_file: chmod: $!\n"; + umask($old_umask); +} + +my ($req, $req_fingerprint); +if (! -e $cert_file) { + open(REQ, '<', $req_file) or die "$req_file: open: $!\n"; + $req = join('', ); + close(REQ); + $req_fingerprint = sha1_hex($req); +} + +my (@states) = + (sub { + # User backed up from first dialog box. + exit(10); + }, + sub { + # Prompt for ports to include in switch. + db_input('netdevs'); + return; + }, + sub { + # Validate the chosen ports. + my (@netdevs) = split(', ', db_get('netdevs')); + if (!@netdevs) { + # No ports chosen. Disable switch. + db_input('no-netdevs'); + return 'prev' if db_go(); + return 'done'; + } elsif (my (@conf_netdevs) = grep(/IP/, @netdevs)) { + # Point out that some ports have configured IP addresses. + db_subst('configured-netdevs', 'configured-netdevs', + join(', ', @conf_netdevs)); + db_input('configured-netdevs'); + return; + } else { + # Otherwise proceed. + return 'skip'; + } + }, + sub { + # In-band or out-of-band controller? + db_input('band'); + return; + }, + sub { + return 'skip' if db_get('band') eq 'out-of-band'; + for (;;) { + db_input('switch-ip'); + return 'prev' if db_go(); + + my $ip = db_get('switch-ip'); + return 'next' if $ip =~ /^dhcp|\d+\.\d+.\d+.\d+$/i; + + db_input('switch-ip-error'); + db_go(); + } + }, + sub { + for (;;) { + my $old_vconn = db_get('controller-vconn'); + db_input('controller-vconn'); + return 'prev' if db_go(); + + my $vconn = db_get('controller-vconn'); + if ($vconn =~ /^(tcp|ssl):([^:]+)(:.*)?/) { + if ($old_vconn ne $vconn + || db_get('pki-host') eq '') { + db_set('pki-host', $2); + } + return 'next'; + } + + db_input('controller-vconn-error'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file && -e $cert_file; + + db_input('pki-host'); + return 'prev' if db_go(); + return; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cacert_file; + + my $pki_host = db_get('pki-host'); + my $url = "http://$pki_host/openflow/pki/controllerca/cacert.pem"; + my $response = $ua->get($url, ':content_file' => $cacert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-cacert-failed', 'url', $url); + db_subst('fetch-cacert-failed', 'error', $response->status_line); + db_subst('fetch-cacert-failed', 'pki-host', $pki_host); + db_input('fetch-cacert-failed'); + db_go(); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('send-cert-req', 'yes'); + db_input('send-cert-req'); + return 'prev' if db_go(); + return 'next' if db_get('send-cert-req') eq 'no'; + + my $pki_host = db_get('pki-host'); + my $url = "http://$pki_host/cgi-bin/ofp-pki-cgi"; + my $response = $ua->post($url, {'type' => 'switch', + 'req' => $req}); + return 'next' if $response->is_success; + + db_subst('send-cert-req-failed', 'url', $url); + db_subst('send-cert-req-failed', 'error', + $response->status_line); + db_subst('send-cert-req-failed', 'pki-host', + $pki_host); + db_input('send-cert-req-failed'); + db_go(); + } + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if $cacert_preverified; + + my ($cacert_fingerprint) = x509_fingerprint($cacert_file); + db_subst('verify-controller-ca', 'fingerprint', $cacert_fingerprint); + db_input('verify-controller-ca'); + return 'prev' if db_go(); + return 'next' if db_get('verify-controller-ca') eq 'yes'; + unlink($cacert_file); + return 'prev'; + }, + sub { + return 'skip' if !ssl_enabled(); + return 'skip' if -e $cert_file; + + for (;;) { + db_set('fetch-switch-cert', 'yes'); + db_input('fetch-switch-cert'); + return 'prev' if db_go(); + exit(1) if db_get('fetch-switch-cert') eq 'no'; + + my $pki_host = db_get('pki-host'); + my $url = "http://$pki_host/openflow/pki/switchca/certs/$req_fingerprint-cert.pem"; + my $response = $ua->get($url, ':content_file' => $cert_file); + if ($response->is_success) { + return 'next'; + } + + db_subst('fetch-switch-cert-failed', 'url', $url); + db_subst('fetch-switch-cert-failed', 'error', + $response->status_line); + db_subst('fetch-switch-cert-failed', 'pki-host', + $pki_host); + db_input('fetch-switch-cert-failed'); + db_go(); + } + }, + sub { + db_input('complete'); + db_go(); + return; + }, + sub { + return 'done'; + }, +); + +my $state = 1; +my $direction = 1; +for (;;) { + my $ret = &{$states[$state]}(); + $ret = db_go() ? 'prev' : 'next' if !defined $ret; + if ($ret eq 'next') { + $direction = 1; + } elsif ($ret eq 'prev') { + $direction = -1; + } elsif ($ret eq 'skip') { + # Nothing to do. + } elsif ($ret eq 'done') { + last; + } else { + die "unknown ret $ret"; + } + $state += $direction; +} + +my %config; +$config{NETDEVS} = join(' ', map(/^(\S+)/, split(', ', db_get('netdevs')))); +if (db_get('band') eq 'in-band') { + $config{IN_BAND} = 'yes'; + $config{SWITCH_IP} = db_get('switch-ip'); +} else { + $config{IN_BAND} = 'no'; +} +$config{CONTROLLER} = db_get('controller-vconn'); +$config{PRIVKEY} = $privkey_file; +$config{CERT} = $cert_file; +$config{CACERT} = $cacert_file; +save_config($default, %config); + +dup2(2, 1); # Get stdout back. +system("/etc/init.d/openflow-switch restart"); + +sub ssl_enabled { + return db_get('controller-vconn') =~ /^ssl:/; +} + +sub db_subst { + my ($question, $key, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = subst($question, $key, $value); + if ($ret && $ret != 30) { + die "Error substituting $value for $key in debconf question " + . "$question: $seen"; + } +} + +sub db_set { + my ($question, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = set($question, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question to $value: $seen"; + } +} + +sub db_get { + my ($question) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = get($question); + if ($ret) { + die "Error getting debconf question $question answer: $seen"; + } + return $seen; +} + +sub db_fset { + my ($question, $flag, $value) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fset($question, $flag, $value); + if ($ret && $ret != 30) { + die "Error setting debconf question $question flag $flag to $value: " + . "$seen"; + } +} + +sub db_fget { + my ($question, $flag) = @_; + $question = "$debconf_owner/$question"; + my ($ret, $seen) = fget($question, $flag); + if ($ret) { + die "Error getting debconf question $question flag $flag: $seen"; + } + return $seen; +} + +sub db_input { + my ($question) = @_; + db_fset($question, "seen", "false"); + + $question = "$debconf_owner/$question"; + my ($ret, $seen) = input('high', $question); + if ($ret && $ret != 30) { + die "Error requesting debconf question $question: $seen"; + } + return $ret; +} + +sub db_go { + my ($ret, $seen) = go(); + if (!defined($ret)) { + exit(1); # Cancel button was pushed. + } + if ($ret && $ret != 30) { + die "Error asking debconf questions: $seen"; + } + return $ret; +} + +sub run_cmd { + my ($cmd) = @_; + return if system($cmd) == 0; + + if ($? == -1) { + die "$cmd: failed to execute: $!\n"; + } elsif ($? & 127) { + die sprintf("$cmd: child died with signal %d, %s coredump\n", + ($? & 127), ($? & 128) ? 'with' : 'without'); + } else { + die sprintf("$cmd: child exited with value %d\n", $? >> 8); + } +} + +sub x509_fingerprint { + my ($file) = @_; + my $cmd = "openssl x509 -noout -in $file -fingerprint"; + open(OPENSSL, '-|', $cmd) or die "$cmd: failed to execute: $!\n"; + my $line = ; + close(OPENSSL); + my ($fingerprint) = $line =~ /SHA1 Fingerprint=(.*)/; + return $line if !defined $fingerprint; + $fingerprint =~ s/://g; + return $fingerprint; +} + +sub find_netdevs { + my ($netdev, %netdevs); + open(IFCONFIG, "/sbin/ifconfig -a|") or die "ifconfig failed: $!"; + while () { + if (my ($nd) = /^([^\s]+)/) { + $netdev = $nd; + $netdevs{$netdev} = "$netdev"; + if (my ($hwaddr) = /HWaddr (\S+)/) { + $netdevs{$netdev} .= " (MAC: $hwaddr)"; + } + } elsif (my ($ip4) = /^\s*inet addr:(\S+)/) { + $netdevs{$netdev} .= " (IP: $ip4)"; + } elsif (my ($ip6) = /^\s*inet6 addr:(\S+)/) { + $netdevs{$netdev} .= " (IPv6: $ip6)"; + } + } + foreach my $nd (keys(%netdevs)) { + delete $netdevs{$nd} if $nd eq 'lo' || $nd =~ /^wmaster/; + } + close(IFCONFIG); + return %netdevs; +} + +sub load_config { + my ($file) = @_; + my ($cmd) = "set -a && . $file && env"; + if (!open(VARS, '-|', $cmd)) { + print STDERR "$cmd: failed to execute: $!\n"; + return; + } + my (%config); + while () { + my ($var, $value) = /^([^=]+)=(.*)$/ or next; + $config{$var} = $value; + } + close(VARS); + return %config; +} + +sub shell_escape { + local $_ = $_[0]; + if (m&^[-a-zA-Z0-9:./%^_+,]*$&) { + return $_; + } else { + s/'/'\\''/; + return "'$_'"; + } +} + +sub shell_assign { + my ($var, $value) = @_; + return $var . '=' . shell_escape($value); +} + +sub save_config { + my ($file, %config) = @_; + my (@lines); + if (open(FILE, '<', $file)) { + @lines = ; + chomp @lines; + close(FILE); + } + + # Replace all existing variable assignments. + for (my ($i) = 0; $i <= $#lines; $i++) { + local $_ = $lines[$i]; + my ($var, $value) = /^\s*([^=#]+)=(.*)$/ or next; + if (exists($config{$var})) { + $lines[$i] = shell_assign($var, $config{$var}); + delete $config{$var}; + } else { + $lines[$i] = "#$lines[$i]"; + } + } + + # Find a place to put any remaining variable assignments. + VAR: + for my $var (keys(%config)) { + my $assign = shell_assign($var, $config{$var}); + + # Replace the last commented-out variable assignment to $var, if any. + for (my ($i) = $#lines; $i >= 0; $i--) { + local $_ = $lines[$i]; + if (/^\s*#\s*$var=/) { + $lines[$i] = $assign; + next VAR; + } + } + + # Find a place to add the var: after the final commented line + # just after a line that contains "$var:". + for (my ($i) = 0; $i <= $#lines; $i++) { + if ($lines[$i] =~ /^\s*#\s*$var:/) { + for (my ($j) = $i + 1; $j <= $#lines; $j++) { + if ($lines[$j] !~ /^\s*#/) { + splice(@lines, $j, 0, $assign); + next VAR; + } + } + } + } + + # Just append it. + push(@lines, $assign); + } + + open(NEWFILE, '>', "$file.tmp") or die "$file.tmp: create: $!\n"; + print NEWFILE join('', map("$_\n", @lines)); + close(NEWFILE); + rename("$file.tmp", $file) or die "$file.tmp: rename to $file: $!\n"; +} diff --git a/debian/ofp-switch-setup.8 b/debian/ofp-switch-setup.8 new file mode 100644 index 00000000..50904cfb --- /dev/null +++ b/debian/ofp-switch-setup.8 @@ -0,0 +1,41 @@ +.TH ofp-switch-setup 8 "June 2008" "OpenFlow" "OpenFlow Manual" + +.SH NAME +ofp\-switch\-setup \- interactive setup for OpenFlow switch + +.SH SYNOPSIS +.B ofp\-switch\-setup + +.SH DESCRIPTION +The \fBofp\-switch\-setup\fR program is an interactive program that +assists the system administrator in configuring an OpenFlow switch, +including the underlying public key infrastructure (PKI). + +.SH OPTIONS +ofp\-switch\-setup does not accept any command-line options. + +.SH FILES +.IP /etc/default/openflow-switch +Main configuration file for OpenFlow switch. + +.IP /etc/openflow-switch/cacert.pem +Default location of CA certificate for OpenFlow controllers. + +.IP /etc/openflow-switch/of0-cert.pem +Default location of certificate for the OpenFlow switch's private key. + +.IP /etc/openflow-switch/of0-privkey.pem +Default location of the OpenFlow switch's private key. This file +should be readable only by \fBroot\fR. + +.IP /etc/openflow-switch/of0-req.pem +Default location of certificate request for the OpenFlow switch's +certificate. This file is not used after the signed certificate +(typically \fB/etc/openflow-switch/of0-cert.pem\fR, above) has been +obtained from the OpenFlow PKI server. + +.SH "SEE ALSO" + +.BR ofp-pki (8), +.BR dpctl (8), +.BR secchan (8) diff --git a/debian/openflow-common.install b/debian/openflow-common.install new file mode 100644 index 00000000..4175c301 --- /dev/null +++ b/debian/openflow-common.install @@ -0,0 +1,2 @@ +utilities/ofp-pki usr/sbin +utilities/vlogconf usr/sbin diff --git a/debian/openflow-common.manpages b/debian/openflow-common.manpages new file mode 100644 index 00000000..282ec329 --- /dev/null +++ b/debian/openflow-common.manpages @@ -0,0 +1,2 @@ +utilities/vlogconf.8 +utilities/ofp-pki.8 diff --git a/debian/openflow-controller.README.Debian b/debian/openflow-controller.README.Debian new file mode 100644 index 00000000..c54e5699 --- /dev/null +++ b/debian/openflow-controller.README.Debian @@ -0,0 +1,5 @@ +README.Debian for openflow-controller +------------------------------------- + +* To reconfigure the controller, edit /etc/default/openflow-controller + and run "/etc/init.d/openflow-controller restart". diff --git a/debian/openflow-controller.default b/debian/openflow-controller.default new file mode 100644 index 00000000..a8275462 --- /dev/null +++ b/debian/openflow-controller.default @@ -0,0 +1,33 @@ +# This is a POSIX shell fragment -*- sh -*- + +# LISTEN: What OpenFlow connection methods should the controller listen on? +# +# This is a space-delimited list of connection methods: +# +# * "pssl:[PORT]": Listen for SSL connections on the specified PORT +# (default: 976). The private key, certificate, and CA certificate +# must be specified below. +# +# * "pctp:[PORT]": Listen for TCP connections on the specified PORT +# (default: 975). Not recommended for security reasons. +# +# * "nl:DP_IDX": Listen on local datapath DP_IDX. Used only if this +# machine is also an OpenFlow switch and not running the secure +# channel, and only if you know what you're doing. +# +LISTEN="pssl:" + +# PRIVKEY: Name of file containing controller's private key. +# Required if SSL enabled. +PRIVKEY=/etc/openflow-controller/privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +CERT=/etc/openflow-controller/cert.pem + +# CACERT: Name of file containing switch CA certificate. +# Required if SSL enabled. +CACERT=/etc/openflow-controller/cacert.pem + +# Additional options to pass to controller, e.g. "--hub" +DAEMON_OPTS="" diff --git a/debian/openflow-controller.dirs b/debian/openflow-controller.dirs new file mode 100644 index 00000000..0a19a9fc --- /dev/null +++ b/debian/openflow-controller.dirs @@ -0,0 +1 @@ +etc/openflow-controller diff --git a/debian/openflow-controller.init b/debian/openflow-controller.init new file mode 100755 index 00000000..121fd76b --- /dev/null +++ b/debian/openflow-controller.init @@ -0,0 +1,269 @@ +#!/bin/sh +# +# Copyright (c) 2007 Javier Fernandez-Sanguino +# +# This is free software; you may redistribute it and/or modify +# it under the terms of the GNU General Public License as +# published by the Free Software Foundation; either version 2, +# or (at your option) any later version. +# +# This is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License with +# the Debian operating system, in /usr/share/common-licenses/GPL; if +# not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA +# +### BEGIN INIT INFO +# Provides: openflow-controller +# Required-Start: $network $local_fs +# Required-Stop: +# Should-Start: $named +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow controller +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin + +DAEMON=/usr/sbin/controller # Introduce the server's location here +NAME=controller # Introduce the short server's name here +DESC=controller # Introduce a short description here +LOGDIR=/var/log/openflow # Log directory to use + +PIDFILE=/var/run/$NAME.pid + +test -x $DAEMON || exit 0 + +. /lib/lsb/init-functions + +# Default options, these can be overriden by the information +# at /etc/default/$NAME +DAEMON_OPTS="" # Additional options given to the server + +DODTIME=10 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +LOGFILE=$LOGDIR/$NAME.log # Server logfile +#DAEMONUSER= # User to run the daemons as. If this value + # is set start-stop-daemon will chuid the server + +# Include defaults if available +default=/etc/default/openflow-controller +if [ -f $default ] ; then + . $default +fi + +# Check that the user exists (if we set a user) +# Does the user exist? +if [ -n "$DAEMONUSER" ] ; then + if getent passwd | grep -q "^$DAEMONUSER:"; then + # Obtain the uid and gid + DAEMONUID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $3}'` + DAEMONGID=`getent passwd |grep "^$DAEMONUSER:" | awk -F : '{print $4}'` + else + log_failure_msg "The user $DAEMONUSER, required to run $NAME does not exist." + exit 1 + fi +fi + + +set -e + +running_pid() { +# Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected server + [ "$cmd" != "$name" ] && return 1 + return 0 +} + +running() { +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` + running_pid $pid $DAEMON || return 1 + return 0 +} + +start_server() { + if [ -z "$LISTEN" ]; then + echo "$default: No connection methods configured, controller disabled" >&2 + exit 0 + fi + + SSL_OPTS= + case $LISTEN in + *ssl*) + : ${PRIVKEY:=/etc/openflow-controller/privkey.pem} + : ${CERT:=/etc/openflow-controller/cert.pem} + : ${CACERT:=/etc/openflow-controller/cacert.pem} + if test ! -e "$PRIVKEY" || test ! -e "$CERT" || + test ! -e "$CACERT"; then + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT"; then + echo "$CACERT: CA certificate missing" >&2 + fi + exit 1 + fi + SSL_OPTS="--private-key=$PRIVKEY --certificate=$CERT --ca-cert=$CACERT" + ;; + esac + +# Start the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --start --pidfile $PIDFILE \ + --exec $DAEMON -- --detach --pidfile=$PIDFILE \ + $LISTEN $DAEMON_OPTS $SSL_OPTS + errcode=$? + else +# if we are using a daemonuser then change the user id + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --chuid $DAEMONUSER --exec $DAEMON -- \ + --detach --pidfile=$PIDFILE $LISTEN $DAEMON_OPTS \ + $SSL_OPTS + errcode=$? + fi + return $errcode +} + +stop_server() { +# Stop the process using the wrapper + if [ -z "$DAEMONUSER" ] ; then + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --exec $DAEMON + errcode=$? + else +# if we are using a daemonuser then look for process that match + start-stop-daemon --stop --quiet --pidfile $PIDFILE \ + --user $DAEMONUSER --exec $DAEMON + errcode=$? + fi + + return $errcode +} + +reload_server() { + [ ! -f "$PIDFILE" ] && return 1 + pid=`cat $PIDFILE` # This is the daemon's pid + # Send a SIGHUP + kill -1 $pid + return $? +} + +force_stop() { +# Force the process to die killing it manually + [ ! -e "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + sleep "$DIETIME"s + if running ; then + kill -9 $pid + sleep "$DIETIME"s + if running ; then + echo "Cannot kill $NAME (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE +} + + +case "$1" in + start) + log_daemon_msg "Starting $DESC " "$NAME" + # Check if it's running first + if running ; then + log_progress_msg "apparently already running" + log_end_msg 0 + exit 0 + fi + if start_server && running ; then + # It's ok, the server started and is running + log_end_msg 0 + else + # Either we could not start it or it is not running + # after we did + # NOTE: Some servers might die some time after they start, + # this code does not try to detect this and might give + # a false positive (use 'status' for that) + log_end_msg 1 + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + if running ; then + # Only stop the server if we see it running + stop_server + log_end_msg $? + else + # If it's not running don't do anything + log_progress_msg "apparently not running" + log_end_msg 0 + exit 0 + fi + ;; + force-stop) + # First try to stop gracefully the program + $0 stop + if running; then + # If it's still running try to kill it more forcefully + log_daemon_msg "Stopping (force) $DESC" "$NAME" + force_stop + log_end_msg $? + fi + ;; + restart|force-reload) + log_daemon_msg "Restarting $DESC" "$NAME" + stop_server + # Wait some sensible amount, some server need this + [ -n "$DIETIME" ] && sleep $DIETIME + start_server + running + log_end_msg $? + ;; + status) + + log_daemon_msg "Checking status of $DESC" "$NAME" + if running ; then + log_progress_msg "running" + log_end_msg 0 + else + log_progress_msg "apparently not running" + log_end_msg 1 + exit 1 + fi + ;; + # Use this if the daemon cannot reload + reload) + log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" + log_warning_msg "cannot re-read the config file (use restart)." + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/debian/openflow-controller.install b/debian/openflow-controller.install new file mode 100644 index 00000000..75ab4356 --- /dev/null +++ b/debian/openflow-controller.install @@ -0,0 +1 @@ +controller/controller usr/sbin diff --git a/debian/openflow-controller.manpages b/debian/openflow-controller.manpages new file mode 100644 index 00000000..c30c912b --- /dev/null +++ b/debian/openflow-controller.manpages @@ -0,0 +1 @@ +controller/controller.8 diff --git a/debian/openflow-controller.postinst b/debian/openflow-controller.postinst new file mode 100755 index 00000000..93e39116 --- /dev/null +++ b/debian/openflow-controller.postinst @@ -0,0 +1,52 @@ +#!/bin/sh +# postinst script for openflow-controller +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + configure) + cd /etc/openflow-controller + if ! test -e cacert.pem; then + ln -s /usr/share/openflow/pki/switchca/cacert.pem cacert.pem + fi + if ! test -e privkey.pem || ! test -e cert.pem; then + oldumask=$(umask) + umask 077 + ofp-pki req+sign tmp controller >/dev/null + mv tmp-privkey.pem privkey.pem + mv tmp-cert.pem cert.pem + mv tmp-req.pem req.pem + chmod go+r cert.pem req.pem + umask $oldumask + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/debian/openflow-datapath-module-_KVERS_.postinst.modules.in b/debian/openflow-datapath-module-_KVERS_.postinst.modules.in new file mode 100755 index 00000000..49e52d63 --- /dev/null +++ b/debian/openflow-datapath-module-_KVERS_.postinst.modules.in @@ -0,0 +1,14 @@ +#!/bin/sh +# postinst script for #PACKAGE# +# +# see: dh_installdeb(1) + +set -e + +depmod -a + +#DEBHELPER# + +exit 0 + + diff --git a/debian/openflow-datapath-source.README.Debian b/debian/openflow-datapath-source.README.Debian new file mode 100644 index 00000000..59965df9 --- /dev/null +++ b/debian/openflow-datapath-source.README.Debian @@ -0,0 +1,31 @@ +OpenFlow for Debian +------------------- + +* How do I build this module the Debian way? + + - Building with module-assistant: + + $ module-assistant auto-install openflow + or + $ m-a a-i openflow + + If kernel source or headers are in a non-standard directory, add + the option -k /path/to/kernel/source with the correct path. + + - Building with make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd /usr/src/kernel-source-2.6.9 + $ make-kpkg --added-modules=openflow modules + + - Building without make-kpkg + + $ cd /usr/src/ + $ tar jxvf openflow.tar.bz2 + $ cd modules/openflow + $ fakeroot debian/rules kdist_image + + If you run this as root, fakeroot is not needed. + + -- OpenFlow Team , Thu, 12 Jun 2008 16:42:38 -0700 diff --git a/debian/openflow-datapath-source.copyright b/debian/openflow-datapath-source.copyright new file mode 100644 index 00000000..f7bcdda3 --- /dev/null +++ b/debian/openflow-datapath-source.copyright @@ -0,0 +1,16 @@ +Upstream Authors: + + The Board of Trustees of The Leland Stanford Junior University + +Copyright: + + Copyright (C) 2008 The Board of Trustees of The Leland Stanford + Junior University + +License: + + Files in the datapath/ and its sub-directories are covered under the GNU + General Public License Version 2. + + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL'. diff --git a/debian/openflow-datapath-source.dirs b/debian/openflow-datapath-source.dirs new file mode 100644 index 00000000..4ddf234a --- /dev/null +++ b/debian/openflow-datapath-source.dirs @@ -0,0 +1 @@ +usr/src/modules/openflow-datapath/debian diff --git a/debian/openflow-pki.apache2 b/debian/openflow-pki.apache2 new file mode 100644 index 00000000..a341c508 --- /dev/null +++ b/debian/openflow-pki.apache2 @@ -0,0 +1 @@ +Alias /openflow/pki/ /usr/share/openflow/pki/ diff --git a/debian/openflow-pki.dirs b/debian/openflow-pki.dirs new file mode 100644 index 00000000..7307777b --- /dev/null +++ b/debian/openflow-pki.dirs @@ -0,0 +1 @@ +etc/apache2/sites-available diff --git a/debian/openflow-pki.install b/debian/openflow-pki.install new file mode 100644 index 00000000..58cfb4e9 --- /dev/null +++ b/debian/openflow-pki.install @@ -0,0 +1 @@ +utilities/ofp-pki-cgi usr/lib/cgi-bin diff --git a/debian/openflow-pki.postinst b/debian/openflow-pki.postinst new file mode 100755 index 00000000..8a687179 --- /dev/null +++ b/debian/openflow-pki.postinst @@ -0,0 +1,49 @@ +#!/bin/sh +# postinst script for openflow +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + # Create certificate authorities. + if test ! -d /usr/share/openflow/pki; then + ofp-pki init + fi + + # Enable site under Apache. + a2ensite openflow-pki >/dev/null + if command -v invoke-rc.d >/dev/null 2>&1; then + invoke-rc.d apache2 force-reload || : + else + [ -x /etc/init.d/apache2 ] && /etc/init.d/apache2 force-reload || : + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 + + diff --git a/debian/openflow-switch.README.Debian b/debian/openflow-switch.README.Debian new file mode 100644 index 00000000..73be13af --- /dev/null +++ b/debian/openflow-switch.README.Debian @@ -0,0 +1,15 @@ +README.Debian for openflow-switch +--------------------------------- + +* The switch must be configured before it can be used. To configure + it interactively, run the ofp-switch-setup program. Alternatively, + edit /etc/default/openflow-switch by hand, then start the switch + manually with "/etc/init.d/openflow-switch start". + +* To use the Linux kernel-based switch implementation, you will need + to build and install the OpenFlow kernel module. To do so, install + the openflow-datapath-source package, then follow the instructions + given in /usr/share/doc/openflow-datapath-source/README.Debian + +* This package does not yet support the userspace switch + implementation. diff --git a/debian/openflow-switch.config b/debian/openflow-switch.config new file mode 100755 index 00000000..7546e02a --- /dev/null +++ b/debian/openflow-switch.config @@ -0,0 +1,4 @@ +#!/bin/sh +set -e +. /usr/share/debconf/confmodule +# Nothing more to do -- the user is responsible for running ofp-switch-setup. diff --git a/debian/openflow-switch.default b/debian/openflow-switch.default new file mode 100644 index 00000000..f2ce5a6a --- /dev/null +++ b/debian/openflow-switch.default @@ -0,0 +1,77 @@ +# This is a POSIX shell fragment -*- sh -*- + +# To configure the secure channel, fill in the following properly and +# uncomment them. Afterward, the secure channel will come up +# automatically at boot time. It can be started immediately with +# /etc/init.d/openflow-switch start +# Alternatively, use the ofp-switch-setup program to do everything +# automatically. + +# NETDEVS: Which network devices should the OpenFlow switch include? +# +# List the network devices that should become part of the OpenFlow +# switch, separated by spaces. At least two devices must be selected +# for this machine to be a useful switch. Unselecting all network +# devices will disable the OpenFlow switch entirely. +# +# The network devices that you select should not be configured with IP +# or IPv6 addresses, even if the switch contacts the controller over +# one of the selected network devices. This is because a running +# OpenFlow switch takes over network devices at a low level: they +# become part of the switch and cannot be used for other purposes. +#NETDEVS="" + +# IN_BAND: The OpenFlow switch must be able to contact the OpenFlow +# controller over the network. It can do so in one of two ways: +# +# * in-band: A single network is used for OpenFlow traffic and other +# data traffic; that is, the switch contacts the controller over one +# of the network devices selected as OpenFlow switch ports in the +# previous question. This is the most common case. +# +# * out-of-band: OpenFlow traffic uses a network separate from the +# data traffic that it controls. If this is the case, the control +# network must already be configured on a network device other than +# one of those selected as an OpenFlow switch port in the previous +# question. +# +# Set IN_BAND to yes for in-band control, or to no for out-of-band +# control. +IN_BAND=yes + +# SWITCH_IP: For in-band communication with the controller, the +# OpenFlow switch must be able to determine its own IP address. Its +# IP address may be configured statically or dynamically: +# +# * For static configuration, specify the switch's IP address as a +# string. +# +# * For dynamic configuration with DHCP (the most common case), +# specify "dhcp". Configuration with DHCP will only work reliably +# if the network topology allows the switch to contact the DHCP +# server before it connects to the OpenFlow controller. +# +# If IN_BAND is set to "no" above, this setting has no effect. +SWITCH_IP=dhcp + +# CONTROLLER: Location of controller. +# One of the following formats: +# tcp:HOST[:PORT] via TCP to PORT (default: 975) on HOST +# ssl:HOST[:PORT] via SSL to PORT (default: 976) on HOST +# The default below assumes that the controller is running locally. +#CONTROLLER="tcp:127.0.0.1" + +# PRIVKEY: Name of file containing switch's private key. +# Required if SSL enabled. +#PRIVKEY=/etc/openflow-switch/of0-privkey.pem + +# CERT: Name of file containing certificate for private key. +# Required if SSL enabled. +#CERT=/etc/openflow-switch/of0-cert.pem + +# CACERT: Name of file containing controller CA certificate. +# Required if SSL enabled. +#CACERT=/etc/openflow-switch/cacert.pem + +# Additional options to pass to secchan, e.g. "--fail=open" +DAEMON_OPTS="" diff --git a/debian/openflow-switch.dirs b/debian/openflow-switch.dirs new file mode 100644 index 00000000..836e4e58 --- /dev/null +++ b/debian/openflow-switch.dirs @@ -0,0 +1,2 @@ +/etc/openflow-switch +/usr/share/lintian/overrides diff --git a/debian/openflow-switch.init b/debian/openflow-switch.init new file mode 100755 index 00000000..1f03df10 --- /dev/null +++ b/debian/openflow-switch.init @@ -0,0 +1,263 @@ +#! /bin/sh +# +# /etc/init.d/openflow-switch +# +# Written by Miquel van Smoorenburg . +# Modified for Debian by Ian Murdock . +# Further changes by Javier Fernandez-Sanguino +# Modified for openflow-switch. +# +# Version: @(#)skeleton 1.9 26-Feb-2001 miquels@cistron.nl +# +### BEGIN INIT INFO +# Provides: openflow-switch +# Required-Start: $network $named $remote_fs $syslog +# Required-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: OpenFlow switch +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/secchan +NAME=secchan +DESC=secchan + +test -x $DAEMON || exit 0 + +LOGDIR=/var/log/openflow +PIDFILE=/var/run/$NAME.pid +DHCLIENT_PIDFILE=/var/run/dhclient.of0.pid +DODTIME=1 # Time to wait for the server to die, in seconds + # If this value is set too low you might not + # let some servers to die gracefully and + # 'restart' will not work + +# Include secchan defaults if available +default=/etc/default/openflow-switch +if [ -f $default ] ; then + . $default +fi + +set -e + +running_pid() +{ + # Check if a given process pid's cmdline matches a given name + pid=$1 + name=$2 + [ -z "$pid" ] && return 1 + [ ! -d /proc/$pid ] && return 1 + cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1` + # Is this the expected child? + [ "$cmd" != "$name" ] && return 1 + return 0 +} + +running() +{ +# Check if the process is running looking at /proc +# (works for all users) + + # No pidfile, probably no daemon present + [ ! -f "$PIDFILE" ] && return 1 + # Obtain the pid and check it against the binary name + pid=`cat $PIDFILE` + running_pid $pid $NAME || return 1 + return 0 +} + +force_stop() { +# Forcefully kill the process + [ ! -f "$PIDFILE" ] && return + if running ; then + kill -15 $pid + # Is it really dead? + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + kill -9 $pid + [ -n "$DODTIME" ] && sleep "$DODTIME"s + if running ; then + echo "Cannot kill $LABEL (pid=$pid)!" + exit 1 + fi + fi + fi + rm -f $PIDFILE + return 0 +} + +must_succeed() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + exit 1 + fi +} + +check_op() { + echo -n "$1: " + shift + if "$@"; then + echo "success." + else + echo " ERROR." + fi +} + +case "$1" in + start) + if test -z "$NETDEVS"; then + echo "$default: No network devices configured, switch disabled" >&2 + echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + if test -z "$CONTROLLER"; then + echo "$default: No controller configured, switch disabled" >&2 + echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2 + exit 0 + fi + if test "$IN_BAND" != yes && test "$IN_BAND" != no; then + echo "$default: IN_BAND must set to 'yes' or 'no'" >&2 + echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + fi + case $CONTROLLER in + tcp:*) + ;; + ssl:*) + : ${PRIVKEY:=/etc/openflow-switch/of0-privkey.pem} + : ${CERT:=/etc/openflow-switch/of0-cert.pem} + : ${CACERT:=/etc/openflow-switch/cacert.pem} + if test ! -e "$PRIVKEY" || test ! -e "$CERT" || + test ! -e "$CACERT"; then + if test ! -e "$PRIVKEY"; then + echo "$PRIVKEY: private key missing" >&2 + fi + if test ! -e "$CERT"; then + echo "$CERT: certificate for private key missing" >&2 + fi + if test ! -e "$CACERT"; then + echo "$CACERT: CA certificate missing" >&2 + fi + echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + fi + ;; + *) + echo "$default: CONTROLLER must be in the form 'ssl:HOST[:PORT]' or 'tcp:HOST[:PORT]'" >&2 + echo "Run ofp-switch-setup or edit /etc/default/openflow-switch to configure" >&2 + exit 1 + esac + + echo -n "Loading openflow_mod: " + if modprobe openflow_mod; then + echo "success." + else + echo " ERROR." + echo "openflow_mod has probably not been built for this kernel." + if ! test -d /usr/share/doc/openflow-datapath-source; then + echo "Install the openflow-datapath-source package, then read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + else + echo "For instructions, read" + echo "/usr/share/doc/openflow-datapath-source/README.Debian" + fi + exit 1 + fi + + must_succeed "Adding datapath" dpctl adddp nl:0 + for netdev in $NETDEVS; do + must_succeed "Adding $netdev to datapath" dpctl addif nl:0 $netdev + done + + if test "$IN_BAND" = yes; then + if test "$SWITCH_IP" = dhcp; then + must_succeed "Temporarily disabling of0" ifconfig of0 down + else + must_succeed "Configuring of0 as $SWITCH_IP" ifconfig of0 $SWITCH_IP + fi + else + must_succeed "Disabling of0" ifconfig of0 down + fi + + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile $PIDFILE \ + --exec $DAEMON -- nl:0 $CONTROLLER --detach --pidfile=$PIDFILE \ + $DAEMON_OPTS $SSL_OPTS + if running; then + echo "$NAME." + else + echo " ERROR." + fi + + if test "$IN_BAND" = yes && test "$SWITCH_IP" = dhcp; then + echo -n "Starting dhclient on of0: " + start-stop-daemon --start --quiet --pidfile $DHCLIENT_PIDFILE \ + --exec /sbin/dhclient -- -q -pf $DHCLIENT_PIDFILE of0 + if running; then + echo "dhclient." + else + echo " ERROR." + fi + fi + ;; + stop) + if test -e /var/run/dhclient.of0.pid; then + echo -n "Stopping dhclient on of0: " + start-stop-daemon --stop --quiet --oknodo \ + --pidfile $DHCLIENT_PIDFILE --exec /sbin/dhclient + echo "dhclient." + fi + + echo -n "Stopping $DESC: " + start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE \ + --exec $DAEMON + echo "$NAME." + + for netdev in $NETDEVS; do + check_op "Removing $netdev from datapath" dpctl delif nl:0 $netdev + done + check_op "Deleting datapath" dpctl deldp nl:0 + ;; + force-stop) + echo -n "Forcefully stopping $DESC: " + force_stop + if ! running; then + echo "$NAME." + else + echo " ERROR." + fi + ;; + reload) + ;; + force-reload) + start-stop-daemon --stop --test --quiet --pidfile \ + $PIDFILE --exec $DAEMON \ + && $0 restart \ + || exit 0 + ;; + restart) + $0 stop || true + $0 start + ;; + status) + echo -n "$LABEL is " + if running ; then + echo "running" + else + echo " not running." + exit 1 + fi + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload|status|force-stop}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/debian/openflow-switch.install b/debian/openflow-switch.install new file mode 100644 index 00000000..96db7278 --- /dev/null +++ b/debian/openflow-switch.install @@ -0,0 +1,4 @@ +switch/switch usr/sbin +secchan/secchan usr/sbin +utilities/dpctl usr/sbin +debian/ofp-switch-setup usr/sbin diff --git a/debian/openflow-switch.links b/debian/openflow-switch.links new file mode 100644 index 00000000..629db1d6 --- /dev/null +++ b/debian/openflow-switch.links @@ -0,0 +1 @@ +/usr/share/modass/packages/default.sh /usr/share/modass/packages/openflow-datapath-source diff --git a/debian/openflow-switch.manpages b/debian/openflow-switch.manpages new file mode 100644 index 00000000..905d0606 --- /dev/null +++ b/debian/openflow-switch.manpages @@ -0,0 +1,4 @@ +debian/ofp-switch-setup.8 +secchan/secchan.8 +switch/switch.8 +utilities/dpctl.8 diff --git a/debian/openflow-switch.overrides b/debian/openflow-switch.overrides new file mode 100644 index 00000000..4ac77aba --- /dev/null +++ b/debian/openflow-switch.overrides @@ -0,0 +1 @@ +debconf-is-not-a-registry diff --git a/debian/openflow-switch.postinst b/debian/openflow-switch.postinst new file mode 100755 index 00000000..c8dc9a4a --- /dev/null +++ b/debian/openflow-switch.postinst @@ -0,0 +1,14 @@ +#!/bin/sh +# postinst script for openflow-switch +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +#DEBHELPER# + +exit 0 + + diff --git a/debian/openflow-switch.templates b/debian/openflow-switch.templates new file mode 100644 index 00000000..c6d4b5e4 --- /dev/null +++ b/debian/openflow-switch.templates @@ -0,0 +1,189 @@ +Template: openflow-switch/netdevs +Type: multiselect +_Choices: ${choices} +_Description: OpenFlow switch network devices: + Choose the network devices that should become part of the OpenFlow + switch. At least two devices must be selected for this machine to be + a useful switch. Unselecting all network devices will disable the + OpenFlow switch entirely. + . + The network devices that you select should not be configured with IP + or IPv6 addresses, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + +Template: openflow-switch/no-netdevs +Type: error +_Description: No network devices were selected. + No network devices were selected for inclusion in the OpenFlow switch. + The switch will be disabled. + +Template: openflow-switch/configured-netdevs +Type: note +_Description: Some Network Devices Have IP or IPv6 Addresses + The following network devices selected to be part of the OpenFlow switch + have IP or IPv6 addresses configured: + . + ${configured-netdevs} + . + This is usually a mistake, even if the switch contacts the controller over + one of the selected network devices. This is because a running + OpenFlow switch takes over network devices at a low level: they + become part of the switch and cannot be used for other purposes. + . + If this is an unintentional mistake, move back and fix the selection, + or de-configure the IP or IPv6 from these network devices. + +Template: openflow-switch/band +Type: select +_Choices: in-band, out-of-band +Default: in-band +_Description: Switch-to-controller access method: + The OpenFlow switch must be able to contact the OpenFlow controller over + the network. It can do so in one of two ways: + . + in-band: A single network is used for OpenFlow traffic and other data + traffic; that is, the switch contacts the controller over one of the + network devices selected as OpenFlow switch netdevs in the previous + question. This is the most common case. + . + out-of-band: OpenFlow traffic uses a network separate from the data traffic + that it controls. If this is the case, the control network must already + be configured on a network device other than one of those selected as + an OpenFlow switch netdev in the previous question. + +Template: openflow-switch/switch-ip +Type: string +Default: dhcp +_Description: Switch IP address: + For in-band communication with the controller, the OpenFlow switch must + be able to determine its own IP address. Its IP address may be configured + statically or dynamically. + . + For static configuration, specify the switch's IP address as a string. + . + For dynamic configuration with DHCP (the most common case), specify "dhcp". + Configuration with DHCP will only work reliably if the network topology + allows the switch to contact the DHCP server before it connects to the + OpenFlow controller. + +Template: openflow-switch/switch-ip-error +Type: error +_Description: The switch IP address is invalid. + The switch IP address must specified as "dhcp" or a valid IP address in + dotted-octet form (e.g. "1.2.3.4"). + +Template: openflow-switch/controller-vconn +Type: string +_Description: Controller location: + Specify how the OpenFlow switch should connect to the OpenFlow controller. + The value should be in form "ssl:HOST[:PORT]" to connect to the controller + over SSL (recommended for security) or "tcp:HOST[:PORT]" to connect over + cleartext TCP. + +Template: openflow-switch/controller-vconn-error +Type: error +_Description: The controller location is invalid. + The controller location must be specifed as "ssl:HOST[:PORT]" to + connect to the controller over SSL (recommended for security) or + "tcp:HOST[:PORT]" to connect over cleartext TCP. + +Template: openflow-switch/pki-host +Type: string +_Description: OpenFlow PKI server host name: + Specify the host name or IP address of the server that hosts the OpenFlow + public key infrastructure (PKI). This is usually the same host as the + OpenFlow controller. + . + The setup process will connect to the OpenFlow PKI server over + HTTP, using the system's configured default HTTP proxy (if any). + +Template: openflow-switch/fetch-cacert-failed +Type: error +_Description: The switch CA certificate could not be retrieved. + Retrieval of ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available on ${pki-host}. If the system is configured to use an HTTP + proxy, also make sure that the HTTP proxy is available and that the + PKI server can be reached through it. + +Template: openflow-switch/verify-controller-ca +Type: select +_Choices: yes, no +Default: yes +_Description: Is ${fingerprint} the controller CA's fingerprint? + If a man-in-the-middle attack is possible in your network + environment, check that the controller CA's fingerprint is really + ${fingerprint}. Answer "yes" if it matches, "no" if + there is a discrepancy. + . + If a man-in-the-middle attack is not a concern, there is no need to + verify the fingerprint. Simply answer "yes". + +Template: openflow-switch/send-cert-req +Type: select +_Choices: yes, no +Default: yes +_Description: Send certificate request to switch CA? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. A signing request can be sent to the PKI + server now. + . + Answer "yes" to send a signing request to the switch CA now. This is + ordinarily the correct choice. There is no harm in sending a given + signing request more than once. + . + Answer "no" to skip sending a signing request to the switch CA. + Unless the request has already been sent to the switch CA, manual + sending of the request and signing will be necessary. + +Template: openflow-switch/send-cert-req-failed +Type: error +_Description: The certificate request could not be sent. + Posting to ${url} failed, with the following status: "${error}". + . + Ensure that the OpenFlow PKI server is correctly configured and + available on ${pki-host}. + +Template: openflow-switch/fetch-switch-cert +Type: select +_Choices: yes, no +_Description: Fetch signed switch certificate from PKI server? + Before it can connect to the controller over SSL, the OpenFlow + switch's key must be signed by the switch certificate authority (CA) + located on the OpenFlow PKI server, which is usually collocated with + the OpenFlow controller. + . + At this point, a signing request has been sent to the switch CA (or + sending a request has been manually skipped), but the signed + certificate has not yet been retrieved. Manual action may need to be + taken at the PKI server to approve the signing request. + . + Answer "yes" to attempt to retrieve the signed switch certificate + from the switch CA. If the switch certificate request has been + signed at the PKI server, this is the correct choice. + . + Answer "no" to postpone switch configuration. The configuration + process must be restarted later, when the switch certificate request + has been signed. + +Template: openflow-switch/fetch-switch-cert-failed +Type: error +_Description: Signed switch certificate could not be retrieved. + The signed switch certificate could not be retrieved from the switch + CA: retrieval of ${url} failed, with the following status: "${error}". + . + This probably indicates that the switch's certificate request has not + yet been signed. If this is the problem, it may be fixed by signing + the certificate request at ${pki-host}, then trying to fetch the + signed switch certificate again. + +Template: openflow-switch/complete +Type: note +_Description: OpenFlow Switch Setup Finished + Setup of this OpenFlow switch is finished. Complete the setup procedure + to enable the switch. diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 00000000..be392661 --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1 @@ +[type: gettext/rfc822deb] openflow-switch.templates diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 00000000..927eb09c --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,432 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: openflow-dev@lists.stanford.edu\n" +"POT-Creation-Date: 2008-06-12 14:45-0700\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: multiselect +#. Choices +#: ../openflow-switch.templates:1001 +msgid "${choices}" +msgstr "" + +#. Type: multiselect +#. Description +#: ../openflow-switch.templates:1002 +msgid "OpenFlow switch network devices:" +msgstr "" + +#. Type: multiselect +#. Description +#: ../openflow-switch.templates:1002 +msgid "" +"Choose the network devices that should become part of the OpenFlow switch. " +"At least two devices must be selected for this machine to be a useful " +"switch. Unselecting all network devices will disable the OpenFlow switch " +"entirely." +msgstr "" + +#. Type: multiselect +#. Description +#: ../openflow-switch.templates:1002 +msgid "" +"The network devices that you select should not be configured with IP or IPv6 " +"addresses, even if the switch contacts the controller over one of the " +"selected network devices. This is because a running OpenFlow switch takes " +"over network devices at a low level: they become part of the switch and " +"cannot be used for other purposes." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:2001 +msgid "No network devices were selected." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:2001 +msgid "" +"No network devices were selected for inclusion in the OpenFlow switch. The " +"switch will be disabled." +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:3001 +msgid "Some Network Devices Have IP or IPv6 Addresses" +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:3001 +msgid "" +"The following network devices selected to be part of the OpenFlow switch " +"have IP or IPv6 addresses configured:" +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:3001 +msgid "${configured-netdevs}" +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:3001 +msgid "" +"This is usually a mistake, even if the switch contacts the controller over " +"one of the selected network devices. This is because a running OpenFlow " +"switch takes over network devices at a low level: they become part of the " +"switch and cannot be used for other purposes." +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:3001 +msgid "" +"If this is an unintentional mistake, move back and fix the selection, or de-" +"configure the IP or IPv6 from these network devices." +msgstr "" + +#. Type: select +#. Choices +#: ../openflow-switch.templates:4001 +msgid "in-band, out-of-band" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:4002 +msgid "Switch-to-controller access method:" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:4002 +msgid "" +"The OpenFlow switch must be able to contact the OpenFlow controller over the " +"network. It can do so in one of two ways:" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:4002 +msgid "" +"in-band: A single network is used for OpenFlow traffic and other data " +"traffic; that is, the switch contacts the controller over one of the network " +"devices selected as OpenFlow switch netdevs in the previous question. This " +"is the most common case." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:4002 +msgid "" +"out-of-band: OpenFlow traffic uses a network separate from the data traffic " +"that it controls. If this is the case, the control network must already be " +"configured on a network device other than one of those selected as an " +"OpenFlow switch netdev in the previous question." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:5001 +msgid "Switch IP address:" +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:5001 +msgid "" +"For in-band communication with the controller, the OpenFlow switch must be " +"able to determine its own IP address. Its IP address may be configured " +"statically or dynamically." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:5001 +msgid "For static configuration, specify the switch's IP address as a string." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:5001 +msgid "" +"For dynamic configuration with DHCP (the most common case), specify \"dhcp" +"\". Configuration with DHCP will only work reliably if the network topology " +"allows the switch to contact the DHCP server before it connects to the " +"OpenFlow controller." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:6001 +msgid "The switch IP address is invalid." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:6001 +msgid "" +"The switch IP address must specified as \"dhcp\" or a valid IP address in " +"dotted-octet form (e.g. \"1.2.3.4\")." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:7001 +msgid "Controller location:" +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:7001 +msgid "" +"Specify how the OpenFlow switch should connect to the OpenFlow controller. " +"The value should be in form \"ssl:HOST[:PORT]\" to connect to the controller " +"over SSL (recommended for security) or \"tcp:HOST[:PORT]\" to connect over " +"cleartext TCP." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:8001 +msgid "The controller location is invalid." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:8001 +msgid "" +"The controller location must be specifed as \"ssl:HOST[:PORT]\" to connect " +"to the controller over SSL (recommended for security) or \"tcp:HOST[:PORT]\" " +"to connect over cleartext TCP." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:9001 +msgid "OpenFlow PKI server host name:" +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:9001 +msgid "" +"Specify the host name or IP address of the server that hosts the OpenFlow " +"public key infrastructure (PKI). This is usually the same host as the " +"OpenFlow controller." +msgstr "" + +#. Type: string +#. Description +#: ../openflow-switch.templates:9001 +msgid "" +"The setup process will connect to the OpenFlow PKI server over HTTP, using " +"the system's configured default HTTP proxy (if any)." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:10001 +msgid "The switch CA certificate could not be retrieved." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:10001 +msgid "Retrieval of ${url} failed, with the following status: \"${error}\"." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:10001 +msgid "" +"Ensure that the OpenFlow PKI server is correctly configured and available on " +"${pki-host}. If the system is configured to use an HTTP proxy, also make " +"sure that the HTTP proxy is available and that the PKI server can be reached " +"through it." +msgstr "" + +#. Type: select +#. Choices +#. Type: select +#. Choices +#. Type: select +#. Choices +#: ../openflow-switch.templates:11001 ../openflow-switch.templates:12001 +#: ../openflow-switch.templates:14001 +msgid "yes, no" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:11002 +msgid "Is ${fingerprint} the controller CA's fingerprint?" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:11002 +msgid "" +"If a man-in-the-middle attack is possible in your network environment, check " +"that the controller CA's fingerprint is really ${fingerprint}. Answer \"yes" +"\" if it matches, \"no\" if there is a discrepancy." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:11002 +msgid "" +"If a man-in-the-middle attack is not a concern, there is no need to verify " +"the fingerprint. Simply answer \"yes\"." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:12002 +msgid "Send certificate request to switch CA?" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:12002 +msgid "" +"Before it can connect to the controller over SSL, the OpenFlow switch's key " +"must be signed by the switch certificate authority (CA) located on the " +"OpenFlow PKI server, which is usually collocated with the OpenFlow " +"controller. A signing request can be sent to the PKI server now." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:12002 +msgid "" +"Answer \"yes\" to send a signing request to the switch CA now. This is " +"ordinarily the correct choice. There is no harm in sending a given signing " +"request more than once." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:12002 +msgid "" +"Answer \"no\" to skip sending a signing request to the switch CA. Unless the " +"request has already been sent to the switch CA, manual sending of the " +"request and signing will be necessary." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:13001 +msgid "The certificate request could not be sent." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:13001 +msgid "Posting to ${url} failed, with the following status: \"${error}\"." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:13001 +msgid "" +"Ensure that the OpenFlow PKI server is correctly configured and available on " +"${pki-host}." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:14002 +msgid "Fetch signed switch certificate from PKI server?" +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:14002 +msgid "" +"Before it can connect to the controller over SSL, the OpenFlow switch's key " +"must be signed by the switch certificate authority (CA) located on the " +"OpenFlow PKI server, which is usually collocated with the OpenFlow " +"controller." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:14002 +msgid "" +"At this point, a signing request has been sent to the switch CA (or sending " +"a request has been manually skipped), but the signed certificate has not yet " +"been retrieved. Manual action may need to be taken at the PKI server to " +"approve the signing request." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:14002 +msgid "" +"Answer \"yes\" to attempt to retrieve the signed switch certificate from the " +"switch CA. If the switch certificate request has been signed at the PKI " +"server, this is the correct choice." +msgstr "" + +#. Type: select +#. Description +#: ../openflow-switch.templates:14002 +msgid "" +"Answer \"no\" to postpone switch configuration. The configuration process " +"must be restarted later, when the switch certificate request has been signed." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:15001 +msgid "Signed switch certificate could not be retrieved." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:15001 +msgid "" +"The signed switch certificate could not be retrieved from the switch CA: " +"retrieval of ${url} failed, with the following status: \"${error}\"." +msgstr "" + +#. Type: error +#. Description +#: ../openflow-switch.templates:15001 +msgid "" +"This probably indicates that the switch's certificate request has not yet " +"been signed. If this is the problem, it may be fixed by signing the " +"certificate request at ${pki-host}, then trying to fetch the signed switch " +"certificate again." +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:16001 +msgid "OpenFlow Switch Setup Finished" +msgstr "" + +#. Type: note +#. Description +#: ../openflow-switch.templates:16001 +msgid "" +"Setup of this OpenFlow switch is finished. Complete the setup procedure to " +"enable the switch." +msgstr "" diff --git a/debian/rules b/debian/rules new file mode 100755 index 00000000..ab44b77f --- /dev/null +++ b/debian/rules @@ -0,0 +1,145 @@ +#!/usr/bin/make -f +# -*- makefile -*- +# Sample debian/rules that uses debhelper. +# +# This file was originally written by Joey Hess and Craig Small. +# As a special exception, when this file is copied by dh-make into a +# dh-make output file, you may use that output file without restriction. +# This special exception was added by Craig Small in version 0.37 of dh-make. +# +# Modified to make a template file for a multi-binary package with separated +# build-arch and build-indep targets by Bill Allombert 2001 + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 + +# This has to be exported to make some magic below work. +export DH_OPTIONS + +# prefix of the target package name +PACKAGE=openflow-datapath-module +# modifieable for experiments or debugging m-a +MA_DIR ?= /usr/share/modass +# load generic variable handling +-include $(MA_DIR)/include/generic.make +# load default rules +-include $(MA_DIR)/include/common-rules.make + +configure: configure-stamp +configure-stamp: + dh_testdir + test -e configure || ./boot.sh + test -e Makefile || \ + ./configure --prefix=/usr --localstatedir=/var --enable-ssl + touch configure-stamp + +#Architecture +build: build-arch build-indep + +build-arch: build-arch-stamp +build-arch-stamp: configure-stamp + $(MAKE) + touch $@ + +build-indep: build-indep-stamp +build-indep-stamp: configure-stamp + $(MAKE) dist distdir=openflow + touch $@ + +clean: + dh_testdir + dh_testroot + rm -f build-arch-stamp build-indep-stamp configure-stamp + [ ! -f Makefile ] || $(MAKE) distclean + dh_clean + debconf-updatepo + +MAJOR=$(shell echo $(KVERS) | sed -e 's/\(...\).*/\1/') +ifeq ($(MAJOR),2.6) +KO=k +l2x=l26 +dpdir=datapath/linux-2.6 +else +KO= +l2x=l24 +dpdir=datapath/linux-2.4 +endif + +kdist_clean: + dh_clean + make KERNELDIR=$(KSRC) KVERREL=$(KVERS) clean + +kdist_config: prep-deb-files + +binary-modules: DSTDIR = $(CURDIR)/debian/$(PKGNAME)/lib/modules/$(KVERS) +binary-modules: prep-deb-files + dh_testdir + dh_testroot + dh_clean -k + tar xzf openflow.tar.gz + cd openflow && ./configure --with-$(l2x)=$(KSRC) + cd openflow && $(MAKE) -C $(dpdir) + install -d -m755 $(DSTDIR) + install -m644 openflow/$(dpdir)/*_mod.$(KO)o $(DSTDIR)/ + dh_installdocs + dh_installchangelogs + dh_compress + dh_fixperms + dh_installdeb + dh_gencontrol -- -v$(VERSION) + dh_md5sums + dh_builddeb --destdir=$(DEB_DESTDIR) + +install: install-indep install-arch +install-indep: MODDIR = $(CURDIR)/debian/openflow-datapath-source/usr/src/modules/openflow-datapath +install-indep: build-indep + dh_testdir + dh_testroot + dh_clean -k -i + dh_installdirs -i + cp openflow.tar.gz $(MODDIR) + cd debian; cp changelog control compat *.modules.in rules $(MODDIR)/debian + cd debian/openflow-datapath-source/usr/src && tar -c modules | bzip2 -9 > openflow-datapath.tar.bz2 && rm -rf modules + install -m644 debian/openflow-pki.apache2 debian/openflow-pki/etc/apache2/sites-available/openflow-pki + dh_install -i + +install-arch: build-arch + dh_testdir + dh_testroot + dh_clean -k -s + dh_installdirs -s + $(MAKE) DESTDIR=$(CURDIR)/debian/openflow install + cp debian/openflow-switch.overrides debian/openflow-switch/usr/share/lintian/overrides/openflow-switch + dh_install -s + +# Must not depend on anything. This is to be called by +# binary-arch/binary-indep +# in another 'make' thread. +binary-common: + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installexamples + dh_installdebconf +# dh_installlogrotate + dh_installinit + dh_installman + dh_link + dh_strip + dh_compress + dh_fixperms + dh_perl + dh_makeshlibs + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb +binary-indep: install-indep + $(MAKE) -f debian/rules DH_OPTIONS=-i binary-common +binary-arch: install-arch + $(MAKE) -f debian/rules DH_OPTIONS=-s binary-common + +binary: binary-arch binary-indep +.PHONY: build clean binary-indep binary-arch binary install install-indep install-arch configure diff --git a/utilities/.gitignore b/utilities/.gitignore index b2c322f2..fbc6f086 100644 --- a/utilities/.gitignore +++ b/utilities/.gitignore @@ -1,4 +1,7 @@ /Makefile /Makefile.in /dpctl +/ofp-pki +/ofp-pki-cgi +/ofp-pki.8 /vlogconf diff --git a/utilities/Makefile.am b/utilities/Makefile.am index 9b3e4df2..566e2add 100644 --- a/utilities/Makefile.am +++ b/utilities/Makefile.am @@ -1,10 +1,28 @@ include ../Make.vars bin_PROGRAMS = vlogconf dpctl -dist_man_MANS = vlogconf.8 dpctl.8 ofp-pki.8 +bin_SCRIPTS = ofp-pki +noinst_SCRIPTS = ofp-pki-cgi + +EXTRA_DIST = ofp-pki.in ofp-pki-cgi.in ofp-pki.8.in +DISTCLEANFILES = ofp-pki ofp-pki-cgi ofp-pki.8 + +dist_man_MANS = vlogconf.8 dpctl.8 +man_MANS = ofp-pki.8 dpctl_SOURCES = dpctl.c dpctl_LDADD = ../lib/libopenflow.la vlogconf_SOURCES = vlogconf.c vlogconf_LDADD = ../lib/libopenflow.la + +pkidir = $(pkgdatadir)/pki + +ofp-pki: ofp-pki.in Makefile + $(do_subst) < $(srcdir)/ofp-pki.in | $(ro_script) > ofp-pki + chmod +x ofp-pki +ofp-pki-cgi: ofp-pki-cgi.in Makefile + $(do_subst) < $(srcdir)/ofp-pki-cgi.in | $(ro_script) > ofp-pki-cgi + chmod +x ofp-pki-cgi +ofp-pki.8: ofp-pki.8.in Makefile + ($(do_subst) && $(ro_man)) < $(srcdir)/ofp-pki.8.in > ofp-pki.8 diff --git a/utilities/ofp-pki b/utilities/ofp-pki deleted file mode 100755 index f9a0735e..00000000 --- a/utilities/ofp-pki +++ /dev/null @@ -1,308 +0,0 @@ -#! /bin/sh -e - -DIR=pki -command= -arg1= -arg2= -prev= -force=no -batch=no -log=ofp-pki.log -for option; do - # This option-parsing mechanism borrowed from a Autoconf-generated - # configure script under the following license: - - # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, - # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. - # This configure script is free software; the Free Software Foundation - # gives unlimited permission to copy, distribute and modify it. - - # If the previous option needs an argument, assign it. - if test -n "$prev"; then - eval $prev=\$option - prev= - continue - fi - case $option in - *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; - *) optarg=yes ;; - esac - - case $dashdash$option in - --) - dashdash=yes ;; - -h|--help) - cat <&2 - { (exit 1); exit 1; }; } -fi -if test -z "$command"; then - echo "$0: missing command name; use --help for help" - exit 1 -fi -exec 3>>$log - -if test "$command" = "new-pki"; then - if test -e "$DIR" && test "$force" != "yes"; then - echo "$0: $DIR already exists" - exit 1 - fi - - if test ! -d "$DIR"; then - mkdir "$DIR" - fi - cd "$DIR" - - if test ! -e dsaparam.pem; then - echo "Generating DSA parameters, please wait..." - openssl dsaparam -out dsaparam.pem 2048 1>&3 2>&3 - fi - - # Create the request configuration. - if test ! -e req.cnf; then - cat > req.cnf < crlnumber - test -e serial || echo 01 > serial - - # Put DSA parameters in directory. - if test ! -e dsaparam.pem; then - cp ../dsaparam.pem . - fi - - # Write CA configuration file. - if test ! -e ca.cnf; then - cat > ca.cnf <<'EOF' -[ req ] -prompt = no -distinguished_name = req_distinguished_name - -[ req_distinguished_name ] -C = US -ST = CA -L = Palo Alto -O = OpenFlow -OU = OpenFlow -CN = OpenFlow - -[ ca ] -default_ca = the_ca - -[ the_ca ] -dir = . # top dir -database = $dir/index.txt # index file. -new_certs_dir = $dir/newcerts # new certs dir -certificate = $dir/cacert.pem # The CA cert -serial = $dir/serial # serial no file -private_key = $dir/private/cakey.pem# CA private key -RANDFILE = $dir/private/.rand # random number file -default_days = 365 # how long to certify for -default_crl_days= 30 # how long before next CRL -default_md = md5 # md to use -policy = policy # default policy -email_in_dn = no # Don't add the email into cert DN -name_opt = ca_default # Subject name display option -cert_opt = ca_default # Certificate display option -copy_extensions = none # Don't copy extensions from request - -# For the CA policy -[ policy ] -countryName = optional -stateOrProvinceName = optional -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional -EOF - fi - - # Create certificate authority. - openssl req -config ca.cnf -nodes \ - -newkey dsa:dsaparam.pem -keyout private/cakey.pem -out careq.pem \ - 1>&3 2>&3 - openssl ca -config ca.cnf -create_serial -out cacert.pem \ - -days 1095 -batch -keyfile private/cakey.pem -selfsign \ - -infiles careq.pem 1>&3 2>&3 - - cd "$oldpwd" - done - exit 0 -fi - -one_arg() { - if test -z "$arg1" || test -n "$arg2"; then - echo "$0: $command must have exactly one argument; use --help for help" - exit 1 - fi -} - -two_args() { - if test -z "$arg1" || test -z "$arg2"; then - echo "$0: $command must have exactly two arguments; use --help for help" - exit 1 - fi -} - -must_not_exist() { - if test -e "$1" && test "$force" != "yes"; then - echo "$0: $1 already exists and --force not supplied" - exit 1 - fi -} - -fingerprint() { - printf "$1-req.pem fingerprint is " - sha1sum "$1-req.pem" | awk '{print $1}' -} - -check_type() { - if test "$1" != switch && test "$1" != controller; then - echo "$0: type argument must be 'switch' or 'controller'" - exit 1 - fi -} - -must_exist() { - if test ! -e "$1"; then - echo "$0: $1 does not exist" - exit 1 - fi -} - -DIR_must_exist() { - if test ! -e "$DIR"; then - echo "$0: $DIR does not exist (need to use --dir or new-pki?)" - exit 1 - elif test ! -d "$DIR"; then - echo "$0: $DIR is not a directory" - exit 1 - fi -} - -make_request() { - must_not_exist "$arg1-privkey.pem" - must_not_exist "$arg1-req.pem" - DIR_must_exist - openssl req -config "$DIR/req.cnf" -text -nodes \ - -newkey "dsa:$DIR/dsaparam.pem" -keyout "$1-privkey.pem" \ - -out "$1-req.pem" 1>&3 2>&3 -} - -sign_request() { - must_exist "$1-req.pem" - must_not_exist "$1-cert.pem" - check_type "$2" - DIR_must_exist - (cd "$DIR/$2ca" && openssl ca -config ca.cnf -batch -in /dev/stdin) \ - < "$1-req.pem" > "$1-cert.pem.tmp" 2>&3 - mv "$1-cert.pem.tmp" "$1-cert.pem" -} - -if test "$command" = req; then - one_arg - make_request "$arg1" - fingerprint "$arg1" -elif test "$command" = sign; then - two_args - fingerprint "$arg1" - if test $batch != yes; then - echo "Does fingerprint match? (yes/no)" - read answer - if test "$answer" != yes; then - echo "Match failure, aborting" - exit 1 - fi - fi - sign_request "$arg1" "$arg2" -elif test "$command" = req+sign; then - two_args - make_request "$arg1" - sign_request "$arg1" "$arg2" - fingerprint "$arg1" -elif test "$command" = verify; then - two_args - must_exist "$arg1-cert.pem" - check_type "$arg2" - DIR_must_exist - openssl verify -CAfile "$DIR/${arg2}ca/cacert.pem" "$arg1-cert.pem" -else - echo "$0: $command command unknown; use --help for help" - exit 1 -fi diff --git a/utilities/ofp-pki-cgi.in b/utilities/ofp-pki-cgi.in new file mode 100755 index 00000000..291352e1 --- /dev/null +++ b/utilities/ofp-pki-cgi.in @@ -0,0 +1,41 @@ +#! @PERL@ + +use CGI; +use Digest::SHA1; +use Fcntl; + +$CGI::POST_MAX = 65536; # Limit POSTs to 64 kB. + +use strict; +use warnings; + +my $pkidir = '@pkidir@'; +my $q = new CGI; + +die unless $q->request_method() eq 'POST'; + +my $type = $q->param('type'); +die unless defined $type; +die unless $type eq 'switch' or $type eq 'controller'; + +my $req = $q->param('req'); +die unless defined $req; +die unless $req =~ /^-----BEGIN CERTIFICATE REQUEST-----$/m; +die unless $req =~ /^-----END CERTIFICATE REQUEST-----$/m; + +my $digest = Digest::SHA1::sha1_hex($req); +my $incoming = "$pkidir/${type}ca/incoming"; +my $dst = "$incoming/$digest-req.pem"; + +sysopen(REQUEST, "$dst.tmp", O_RDWR | O_CREAT | O_EXCL, 0600) + or die "sysopen $dst.tmp: $!"; +print REQUEST $req; +close(REQUEST) or die "close $dst.tmp: $!"; + +rename("$dst.tmp", $dst) or die "rename $dst.tmp to $dst: $!"; + +print $q->header('text/html', '204 No response'); + +# Local Variables: +# mode: perl +# End: diff --git a/utilities/ofp-pki.8 b/utilities/ofp-pki.8 deleted file mode 100644 index 113b3256..00000000 --- a/utilities/ofp-pki.8 +++ /dev/null @@ -1,145 +0,0 @@ -.TH ofp-pki 8 "May 2008" "OpenFlow" "OpenFlow Manual" - -.SH NAME -ofp\-pki \- OpenFlow public key infrastructure management utility - -.SH SYNOPSIS -\fBofp\-pki\fR [\fIOPTIONS\fR] \fICOMMAND\fR [\fIARGS\fR] -.sp -Commands with their arguments: -.br -\fBofp\-pki\fR \fBnew-pki\fR -.br -\fBofp\-pki\fR \fBreq\fR \fINAME\fR -.br -\fBofp\-pki\fR \fBsign\fR \fINAME\fR \fITYPE\fR -.br -\fBofp\-pki\fR \fBreq+sign\fR \fINAME\fR \fITYPE\fR -.br -\fBofp\-pki\fR \fBverify\fR \fINAME\fR \fITYPE\fR -.sp -The available options are: -.br -[\fB-d\fR \fIDIR\fR | \fB--dir=\fR\fIDIR\fR] [\fB-f\fR | \fB--force\fR] [\fB-b\fR | \fB--batch\fR] [\fB-l\fR \fIFILE\fR | \fB--log=\fIFILE\fR] [\fB-h\fR | \fB--help\fR] - -.SH DESCRIPTION -The \fBofp-pki\fR program sets up and manages a public key -infrastructure for use with OpenFlow. It is intended to be a simple -interface for organizations that do not have an established public key -infrastructure. Other PKI tools can substitute for or supplement the -use of \fBofp-pki\fR. - -\fBofp-pki\fR uses \fBopenssl\fR(1) for certificate management and key -generation. - -The commands supported by \fBofp-pki\fR are: - -.TP -\fBnew-pki\fR -Creates a new PKI directory (by default named \fBpki\fR) and populates -it with a pair of certificate authorities for controllers and -switches. - -This command should ideally be run on a high-security machine separate -from any OpenFlow controller or switch, called the CA machine. The -files \fBpki/controllerca/cacert.pem\fR and -\fBpki/switchca/cacert.pem\fR that it produces will need to be copied -over to the OpenFlow switches and controllers, respectively. Their -contents may safely be made public. - -Other files generated by \fBnew-pki\fR may remain on the CA machine. -The files \fBpki/controllerca/private/cakey.pem\fR and -\fBpki/switchca/private/cakey.pem\fR have particularly sensitive -contents that should not be exposed. - -.TP -\fBreq\fR \fINAME\fR -Generates a new private key named \fINAME\fR\fB-privkey.pem\fR and -corresponding certificate request named \fINAME\fR\fB-req.pem\fR. -The private key can be intended for use by a switch or a controller. - -This command should ideally be run on the switch or controller that -will use the private key to identify itself. The file -\fINAME\fR\fB-req.pem\fR must be copied to the CA machine for signing -with the \fBsign\fR command (below). - -This command will output a fingerprint to stdout as its final step. -Write down the fingerprint and take it to the CA machine before -continuing with the \fBsign\fR step. - -\fINAME\fR\fB-privkey.pem\fR has sensitive contents that should not be -exposed. \fINAME\fR\fB-req.pem\fR may be safely made public. - -.TP -\fBsign\fR \fINAME\fR \fITYPE\fR -Signs the certificate request named \fINAME\fR\fB-req.pem\fR that was -produced in the previous step, producing a certificate named -\fINAME\fR\fB-cert.pem\fR. \fITYPE\fR, which must be \fBswitch\fR or -\fBcontroller\fR, indicates the use for which the key is being -certified. - -This command must be run on the CA machine. - -The command will output a fingerprint to stdout and request that you -verify that it is the same fingerprint output by the \fBreq\fR -command. This ensures that the request being signed is the same one -produced by \fBreq\fR. - -The file \fINAME\fR\fB-cert.pem\fR will need to be copied back to the -switch or controller for which it is intended. Its contents may -safely be made public. - -.TP -\fBreq+sign\fR \fINAME\fR \fITYPE\fR -Combines the \fBreq\fR and \fBsign\fR commands into a single step, -outputting all the files produced by each. The -\fINAME\fR\fB-privkey.pem\fR and \fINAME\fR\fB-cert.pem\fR files must -be copied securely to the switch or controller. -\fINAME\fR\fB-privkey.pem\fR has sensitive contents and must not be -exposed in transit. Afterward, it should be deleted from the CA -machine. - -This combined method is, theoretically, less secure than the -individual steps performed separately on two different machines, -because there is additional potential for exposure of the private -key. However, it is also more convenient. - -.TP -\fBverify\fR \fINAME\fR \fITYPE\fR -Verifies that \fINAME\fR\fB-cert.pem\fR is a valid certificate for the -given \fITYPE\fR of use (either \fBswitch\fR or \fBcontroller\fR). If -the certificate is valid for this use, it prints the message -``\fINAME\fR\fB-cert.pem\fR: OK''; otherwise, it prints an error -message. - -.SH OPTIONS -.TP -[\fB-d\fR \fIDIR\fR | \fB--dir=\fR\fIDIR\fR] -Specifies the location of the PKI hierarchy to be used or created by -the command (default: \fBpki\fR under the current directory). The -\fBreq\fR command does not need access to a PKI hierarchy. - -.TP -[\fB-f\fR | \fB--force\fR] -By default, \fBofp-pki\fR will not overwrite existing files or -directories. This option overrides this behavior. - -.TP -[\fB-b\fR | \fB--batch\fR] -Suppresses the interactive verification of fingerprints that the -\fBsign\fR command by default requires. - -.TP -[\fB-l\fR \fIFILE\fR | \fB--log=\fIFILE\fR] -Sets the log file to \fIFILE\fR (default: ofp-pki.log). - -.TP -[\fB-h\fR | \fB--help\fR] -Prints a help usage message and exits. - -.SH "SEE ALSO" - -.BR dpctl (8), -.BR switch (8), -.BR secchan (8), -.BR controller (8) diff --git a/utilities/ofp-pki.in b/utilities/ofp-pki.in new file mode 100755 index 00000000..74a53c60 --- /dev/null +++ b/utilities/ofp-pki.in @@ -0,0 +1,530 @@ +#! /bin/sh -e + +pkidir='@pkidir@' +command= +prev= +force=no +batch=no +log=ofp-pki.log +for option; do + # This option-parsing mechanism borrowed from a Autoconf-generated + # configure script under the following license: + + # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, + # 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + # This configure script is free software; the Free Software Foundation + # gives unlimited permission to copy, distribute and modify it. + + # If the previous option needs an argument, assign it. + if test -n "$prev"; then + eval $prev=\$option + prev= + continue + fi + case $option in + *=*) optarg=`expr "X$option" : '[^=]*=\(.*\)'` ;; + *) optarg=yes ;; + esac + + case $dashdash$option in + --) + dashdash=yes ;; + -h|--help) + cat <&2 + exit 1 + ;; + *) + if test -z "$command"; then + command=$option + elif test -z "${arg1+set}"; then + arg1=$option + elif test -z "${arg2+set}"; then + arg2=$option + else + echo "$option: only two arguments may be specified" >&2 + exit 1 + fi + ;; + esac + shift +done +if test -n "$prev"; then + option=--`echo $prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $option" >&2 + { (exit 1); exit 1; }; } +fi +if test -z "$command"; then + echo "$0: missing command name; use --help for help" >&2 + exit 1 +fi + +if test "$command" = "init"; then + if test -e "$pkidir" && test "$force" != "yes"; then + echo "$0: $pkidir already exists" >&2 + exit 1 + fi + + if test ! -d "$pkidir"; then + mkdir -p "$pkidir" + fi + cd "$pkidir" + exec 3>>$log + + if test ! -e dsaparam.pem; then + echo "Generating DSA parameters, please wait..." >&2 + openssl dsaparam -out dsaparam.pem 2048 1>&3 2>&3 + fi + + # Create the request configuration. + if test ! -e req.cnf; then + cat > req.cnf <&2 + oldpwd=$PWD + mkdir -p $ca + cd $ca + + mkdir -p certs crl newcerts + mkdir -p -m 0700 private + mkdir -p -m 0733 incoming + touch index.txt + test -e crlnumber || echo 01 > crlnumber + test -e serial || echo 01 > serial + + # Put DSA parameters in directory. + if test ! -e dsaparam.pem; then + cp ../dsaparam.pem . + fi + + # Write CA configuration file. + if test ! -e ca.cnf; then + cat > ca.cnf <<'EOF' +[ req ] +prompt = no +distinguished_name = req_distinguished_name + +[ req_distinguished_name ] +C = US +ST = CA +L = Palo Alto +O = OpenFlow +OU = OpenFlow +CN = OpenFlow + +[ ca ] +default_ca = the_ca + +[ the_ca ] +dir = . # top dir +database = $dir/index.txt # index file. +new_certs_dir = $dir/newcerts # new certs dir +certificate = $dir/cacert.pem # The CA cert +serial = $dir/serial # serial no file +private_key = $dir/private/cakey.pem# CA private key +RANDFILE = $dir/private/.rand # random number file +default_days = 365 # how long to certify for +default_crl_days= 30 # how long before next CRL +default_md = md5 # md to use +policy = policy # default policy +email_in_dn = no # Don't add the email into cert DN +name_opt = ca_default # Subject name display option +cert_opt = ca_default # Certificate display option +copy_extensions = none # Don't copy extensions from request + +# For the CA policy +[ policy ] +countryName = optional +stateOrProvinceName = optional +organizationName = match +organizationalUnitName = optional +commonName = supplied +emailAddress = optional +EOF + fi + + # Create certificate authority. + openssl req -config ca.cnf -nodes \ + -newkey dsa:dsaparam.pem -keyout private/cakey.pem -out careq.pem \ + 1>&3 2>&3 + openssl ca -config ca.cnf -create_serial -out cacert.pem \ + -days 1095 -batch -keyfile private/cakey.pem -selfsign \ + -infiles careq.pem 1>&3 2>&3 + chmod 0700 private/cakey.pem + + cd "$oldpwd" + done + exit 0 +fi + +one_arg() { + if test -z "$arg1" || test -n "$arg2"; then + echo "$0: $command must have exactly one argument; use --help for help" >&2 + exit 1 + fi +} + +zero_or_one_args() { + if test -n "$arg2"; then + echo "$0: $command must have zero or one arguments; use --help for help" >&2 + exit 1 + fi +} + +one_or_two_args() { + if test -z "$arg1"; then + echo "$0: $command must have one or two arguments; use --help for help" >&2 + exit 1 + fi +} + +must_not_exist() { + if test -e "$1" && test "$force" != "yes"; then + echo "$0: $1 already exists and --force not supplied" >&2 + exit 1 + fi +} + +resolve_prefix() { + test -n "$type" || exit 123 # Forgot to call check_type? + + case $1 in + ????*) + ;; + *) + echo "Prefix $arg1 is too short (less than 4 hex digits)" + exit 0 + ;; + esac + + fingerprint=$(cd "$pkidir/${type}ca/incoming" && echo "$1"*-req.pem + | sed 's/-req\.pem$//') + case $fingerprint in + "${1}*") + echo "No certificate requests matching $1" + exit 1 + ;; + *" "*) + echo "$1 matches more than one certificate request:" + echo $fingerprint | sed 's/ /\ +/g' + exit 1 + ;; + *) + # Nothing to do. + ;; + esac + req="$pkidir/${type}ca/incoming/$fingerprint-req.pem" + cert="$pkidir/${type}ca/certs/$fingerprint-cert.pem" +} + +make_tmpdir() { + TMP=/tmp/ofp-pki.tmp$$ + rm -rf $TMP + trap "rm -rf $TMP" 0 + mkdir -m 0700 $TMP +} + +fingerprint() { + local file=$1 + local name=${1-$2} + local date=$(date -r $file) + local fingerprint + if grep -q -e '-BEGIN CERTIFICATE-' "$file"; then + fingerprint=$(openssl x509 -noout -in "$file" -fingerprint | + sed 's/SHA1 Fingerprint=//' | tr -d ':') + else + fingerprint=$(sha1sum "$file" | awk '{print $1}') + fi + printf "$name\\t$date\\n" + case $file in + $fingerprint*) + printf "\\t(correct fingerprint in filename)\\n" + ;; + *) + printf "\\tfingerprint $fingerprint\\n" + ;; + esac +} + +verify_fingerprint() { + fingerprint "$@" + if test $batch != yes; then + echo "Does fingerprint match? (yes/no)" + read answer + if test "$answer" != yes; then + echo "Match failure, aborting" >&2 + exit 1 + fi + fi +} + +check_type() { + if test x = x"$1"; then + type=switch + elif test "$1" = switch || test "$1" = controller; then + type=$1 + else + echo "$0: type argument must be 'switch' or 'controller'" >&2 + exit 1 + fi +} + +parse_age() { + number=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\1/') + unit=$(echo $1 | sed 's/^\([0-9]\+\)\([[:alpha:]]\+\)/\2/') + case $unit in + s) + factor=1 + ;; + min) + factor=60 + ;; + h) + factor=3600 + ;; + day) + factor=86400 + ;; + *) + echo "$1: age not in the form Ns, Nmin, Nh, Nday (e.g. 1day)" >&2 + exit 1 + ;; + esac + echo $(($number * $factor)) +} + +must_exist() { + if test ! -e "$1"; then + echo "$0: $1 does not exist" >&2 + exit 1 + fi +} + +pkidir_must_exist() { + if test ! -e "$pkidir"; then + echo "$0: $pkidir does not exist (need to run 'init' or use '--dir'?)" >&2 + exit 1 + elif test ! -d "$pkidir"; then + echo "$0: $pkidir is not a directory" >&2 + exit 1 + fi +} + +make_request() { + must_not_exist "$arg1-privkey.pem" + must_not_exist "$arg1-req.pem" + pkidir_must_exist + openssl req -config "$pkidir/req.cnf" -text -nodes \ + -newkey "dsa:$pkidir/dsaparam.pem" -keyout "$1-privkey.pem" \ + -out "$1-req.pem" 1>&3 2>&3 +} + +sign_request() { + must_exist "$1" + must_not_exist "$2" + pkidir_must_exist + + (cd "$pkidir/${type}ca" && + openssl ca -config ca.cnf -batch -in /dev/stdin) \ + < "$1" > "$2.tmp$$" 2>&3 + mv "$2.tmp$$" "$2" +} + +glob() { + local files=$(echo $1) + if test "$files" != "$1"; then + echo "$files" + fi +} + +case $log in + /*) + exec 3>>$log || true + ;; + *) + exec 3>>$pkidir/$log || true + ;; +esac + +if test "$command" = req; then + one_arg + + make_request "$arg1" + fingerprint "$arg1-req.pem" +elif test "$command" = sign; then + one_or_two_args + check_type "$arg2" + verify_fingerprint "$arg1-req.pem" + + sign_request "$arg1-req.pem" "$arg2-cert.pem" +elif test "$command" = req+sign; then + one_or_two_args + check_type "$arg2" + + make_request "$arg1" + sign_request "$arg1-req.pem" "$arg1-cert.pem" + fingerprint "$arg1-req.pem" +elif test "$command" = verify; then + one_or_two_args + must_exist "$arg1-cert.pem" + check_type "$arg2" + + pkidir_must_exist + openssl verify -CAfile "$pkidir/${type}ca/cacert.pem" "$arg1-cert.pem" +elif test "$command" = fingerprint; then + one_arg + + fingerprint "$arg1" +elif test "$command" = ls; then + check_type "$arg2" + + cd "$pkidir/${type}ca/incoming" + for file in $(glob "$arg1*-req.pem"); do + fingerprint $file + done +elif test "$command" = flush; then + check_type "$arg1" + + rm -f "$pkidir/${type}ca/incoming/"* +elif test "$command" = reject; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + rm -f "$req" +elif test "$command" = approve; then + one_or_two_args + check_type "$arg2" + resolve_prefix "$arg1" + + make_tmpdir + cp "$req" "$TMP/$req" + verify_fingerprint "$TMP/$req" + sign_request "$TMP/$req" + rm -f "$req" "$TMP/$req" +elif test "$command" = prompt; then + zero_or_one_args + check_type "$arg1" + + make_tmpdir + cd "$pkidir/${type}ca/incoming" + for req in $(glob "*-req.pem"); do + cp "$req" "$TMP/$req" + + cert=$(echo "$pkidir/${type}ca/certs/$req" | + sed 's/-req.pem/-cert.pem/') + if test -f $cert; then + echo "Request $req already approved--dropping duplicate request" + rm -f "$req" "$TMP/$req" + continue + fi + + echo + echo + fingerprint "$TMP/$req" "$req" + printf "Disposition for this request (skip/approve/reject)? " + read answer + case $answer in + approve) + echo "Approving $req" + sign_request "$TMP/$req" "$cert" + rm -f "$req" "$TMP/$req" + ;; + r*) + echo "Rejecting $req" + rm -f "$req" "$TMP/$req" + ;; + *) + echo "Skipping $req" + ;; + esac + done +elif test "$command" = expire; then + zero_or_one_args + cutoff=$(($(date +%s) - $(parse_age ${arg1-1day}))) + for type in switch controller; do + cd "$pkidir/${type}ca/incoming" || exit 1 + for file in $(glob "*"); do + time=$(date -r "$file" +%s) + if test "$time" -lt "$cutoff"; then + rm -f "$file" + fi + done + done +else + echo "$0: $command command unknown; use --help for help" >&2 + exit 1 +fi