tor-commits
Threads by month
- ----- 2025 -----
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
July 2012
- 14 participants
- 949 discussions

[vidalia-plugins/master] Add bandwidth graph implementation as a plugin
by chiiph@torproject.org 20 Jul '12
by chiiph@torproject.org 20 Jul '12
20 Jul '12
commit f64298fbeb7cc576f43bb00f3c0b6715dc63d385
Author: Tomás Touceda <chiiph(a)torproject.org>
Date: Fri Jul 20 15:14:26 2012 -0300
Add bandwidth graph implementation as a plugin
---
bwgraph/bwgraph.js | 149 +++++++++++++++
bwgraph/bwgraph.ui | 485 +++++++++++++++++++++++++++++++++++++++++++++++++
bwgraph/graphframe.js | 297 ++++++++++++++++++++++++++++++
bwgraph/info.xml | 11 +
4 files changed, 942 insertions(+), 0 deletions(-)
diff --git a/bwgraph/bwgraph.js b/bwgraph/bwgraph.js
new file mode 100644
index 0000000..565d6a0
--- /dev/null
+++ b/bwgraph/bwgraph.js
@@ -0,0 +1,149 @@
+importExtension("qt");
+importExtension("qt.core");
+importExtension("qt.gui");
+importExtension("qt.uitools");
+
+var bwgraph = {
+ From: "From",
+ Sent: "Sent",
+ Recv: "Recv",
+
+ SETTING_DORECV: "DoRecv",
+ SETTING_DOSEND: "DoSend",
+ SETTING_ALWAYS_ON_TOP: "AlwaysOnTop",
+ SETTING_STYLE: "GraphStyle",
+
+ start: function() {
+ vdebug("Bwhistory@start");
+ torControl["bandwidthUpdate(quint64, quint64)"].connect(this, this.saveBandwidth);
+ this.createGUI();
+ this.loadSettings();
+
+ this.recv = parseInt(this.tab.getSetting(this.Sent, 0));
+ this.sent = parseInt(this.tab.getSetting(this.Recv, 0));
+ this.from = this.tab.getSetting(this.From, "");
+
+ if(this.from.length == 0)
+ this.from = QDateTime.currentDateTime().toString();
+ },
+
+ saveBandwidth: function(recv, sent) {
+ this.recv += recv;
+ this.sent += sent;
+
+ this.tab.saveSetting(this.Recv, this.recv.toString());
+ this.tab.saveSetting(this.Sent, this.sent.toString());
+ this.tab.saveSetting(this.From, this.from);
+
+ this.lblFrom.text = this.from;
+ this.lblSent.text = (this.sent/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+ this.lblRecv.text = (this.recv/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+ this.frame.addPoints(recv/1024.0, sent/1024.0);
+ },
+
+ resetCounters: function() {
+ this.recv = 0;
+ this.sent = 0;
+ this.from = QDateTime.currentDateTime().toString();
+ this.saveBandwidth(0,0);
+ },
+
+ createGUI: function() {
+ this.tab = new VidaliaTab("Bandwidth Graph", "BandwidthGraph");
+
+ var file = new QFile(pluginPath+"/bwgraph/bwgraph.ui");
+ var loader = new QUiLoader(this.tab);
+ file.open(QIODevice.ReadOnly);
+ this.widget = loader.load(file);
+ var layout = new QVBoxLayout(this.tab);
+ vdebug(layout);
+ layout.sizeConstraint = QLayout.SetMinAndMaxSize;
+ layout.addWidget(this.widget, 100, Qt.AlignCenter);
+ this.tab.setLayout(layout);
+ file.close();
+
+ this.grpBandwidth = this.widget.children()[findWidget(this.widget, "grpBandwidth")];
+
+ var graphFrame = this.widget.children()[findWidget(this.widget, "graphFrame")];
+ var graphLayout = graphFrame.children()[findWidget(graphFrame, "graphLayout")];
+
+ this.frame = new GraphFrame();
+ graphLayout.addWidget(this.frame, 1000, Qt.AlignLeft);
+
+ this.btnHistory = this.widget.children()[findWidget(this.widget, "btnHistory")];
+ this.btnSettings = this.widget.children()[findWidget(this.widget, "btnSettings")];
+ this.btnReset = this.widget.children()[findWidget(this.widget, "btnReset")];
+
+ this.frmSettings = this.widget.children()[findWidget(this.widget, "frmSettings")];
+ this.btnSaveSettings = this.frmSettings.children()[findWidget(this.frmSettings, "btnSaveSettings")];
+ this.btnCancelSettings = this.frmSettings.children()[findWidget(this.frmSettings, "btnCancelSettings")];
+ this.cmbGraphStyle = this.frmSettings.children()[findWidget(this.frmSettings, "cmbGraphStyle")];
+ this.chkReceiveRate = this.frmSettings.children()[findWidget(this.frmSettings, "chkReceiveRate")];
+ this.chkSendRate = this.frmSettings.children()[findWidget(this.frmSettings, "chkSendRate")];
+ this.chkAlwaysOnTop = this.frmSettings.children()[findWidget(this.frmSettings, "chkAlwaysOnTop")];
+
+ this.lblFrom = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblFrom")];
+ this.lblSent = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblSent")];
+ this.lblRecv = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "lblRecv")];
+ this.btnResetHistory = this.grpBandwidth.children()[findWidget(this.grpBandwidth, "btnResetHistory")];
+
+ this.lblFrom.text = this.from;
+ this.lblSent.text = (this.sent/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+ this.lblRecv.text = (this.recv/1024/1024).toFixed(4).toString() + " <b>Mb/s</b>";
+
+ this.btnResetHistory["clicked()"].connect(this, this.resetCounters);
+
+ this.btnHistory["toggled(bool)"].connect(this, this.toggleHistory);
+ this.btnSettings["toggled(bool)"].connect(this, this.toggleSettings);
+ this.toggleHistory(false);
+ this.toggleSettings(false);
+
+ this.btnReset["clicked()"].connect(this.frame, this.frame.resetGraph);
+ this.btnSaveSettings["clicked()"].connect(this, this.saveSettings);
+ },
+
+ saveSettings: function() {
+ vdebug("Bwhistory@saveSettings");
+ this.tab.saveSetting(this.SETTING_DORECV, (this.chkReceiveRate.checkState() == Qt.Checked) ? "true" : "false");
+ this.tab.saveSetting(this.SETTING_DOSEND, (this.chkSendRate.checkState() == Qt.Checked) ? "true" : "false");
+ this.tab.saveSetting(this.SETTING_STYLE, this.cmbGraphStyle.currentIndex);
+ this.tab.saveSetting(this.SETTING_ALWAYS_ON_TOP, (this.chkAlwaysOnTop.checkState() == Qt.Checked) ? "true" : "false");
+ this.frame.graphStyle = this.cmbGraphStyle.currentIndex;
+ this.frame.showRecv = (this.chkReceiveRate.checkState() == Qt.Checked);
+ this.frame.showSend = (this.chkSendRate.checkState() == Qt.Checked);
+ this.toggleSettings(false);
+ },
+
+ loadSettings: function() {
+ vdebug("Bwhistory@loadSettings");
+ var dorecv = this.tab.getSetting(this.SETTING_DORECV, "true") != "false";
+ var dosend = this.tab.getSetting(this.SETTING_DOSEND, "true") != "false";
+ this.frame.graphStyle = this.tab.getSetting(this.SETTING_STYLE, 0);
+ var alwaysontop = this.tab.getSetting(this.SETTING_ALWAYS_ON_TOP, "false") != "false";
+
+ this.chkReceiveRate.setCheckState(dorecv ? Qt.Checked : Qt.Unchecked);
+ this.chkSendRate.setCheckState(dosend ? Qt.Checked : Qt.Unchecked);
+ this.chkAlwaysOnTop.setCheckState(alwaysontop ? Qt.Checked : Qt.Unchecked);
+ this.cmbGraphStyle.currentIndex = this.frame.graphStyle;
+ this.frame.showRecv = dorecv;
+ this.frame.showSend = dosend;
+ },
+
+ buildGUI: function() {
+ vdebug("Bwhistory@buildGUI");
+ return this.tab;
+ },
+
+ toggleHistory: function(toggle) {
+ this.grpBandwidth.setVisible(toggle);
+ },
+
+ toggleSettings: function(toggle) {
+ this.frmSettings.setVisible(toggle);
+ },
+
+ stop: function() {
+ vdebug("Bwhistory@stop");
+ this.saveBandwidth(0,0);
+ },
+};
diff --git a/bwgraph/bwgraph.ui b/bwgraph/bwgraph.ui
new file mode 100644
index 0000000..967ceda
--- /dev/null
+++ b/bwgraph/bwgraph.ui
@@ -0,0 +1,485 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>Form</class>
+ <widget class="QWidget" name="Form">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>548</width>
+ <height>499</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_3">
+ <item row="3" column="0">
+ <widget class="QGroupBox" name="grpBandwidth">
+ <property name="title">
+ <string>Bandwidth history</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="2" column="1" colspan="2">
+ <widget class="QLabel" name="lblSent">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="lblSentLabel">
+ <property name="text">
+ <string><b>Data Sent:</b></string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" colspan="2">
+ <widget class="QLabel" name="lblRecv">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="lblFromLabel">
+ <property name="text">
+ <string><b>Since:</b></string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QLabel" name="lblSentLabel_2">
+ <property name="text">
+ <string><b>Data Recieved:</b></string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="2">
+ <widget class="QPushButton" name="btnResetHistory">
+ <property name="text">
+ <string>Reset history</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="2">
+ <widget class="QLabel" name="lblFrom">
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="3">
+ <spacer name="horizontalSpacer">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>QSizePolicy::Maximum</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>1000</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="5" column="0" colspan="2">
+ <spacer name="horizontalSpacer_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="4" column="0">
+ <widget class="QFrame" name="frmSettings">
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QGridLayout" name="gridLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <property name="horizontalSpacing">
+ <number>10</number>
+ </property>
+ <property name="verticalSpacing">
+ <number>0</number>
+ </property>
+ <property name="margin">
+ <number>5</number>
+ </property>
+ <item row="0" column="0">
+ <widget class="QCheckBox" name="chkReceiveRate">
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Receive Rate</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <widget class="QCheckBox" name="chkSendRate">
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string/>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Send Rate</string>
+ </property>
+ <property name="checked">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0">
+ <widget class="QCheckBox" name="chkAlwaysOnTop">
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>Always on Top</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3">
+ <widget class="QLabel" name="lblGraphStyle">
+ <property name="text">
+ <string>Style</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="4">
+ <widget class="QComboBox" name="cmbGraphStyle">
+ <item>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../vidalia/src/vidalia/res/vidalia.qrc">
+ <normaloff>:/images/16x16/graph-line.png</normaloff>:/images/16x16/graph-line.png</iconset>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../../vidalia/src/vidalia/res/vidalia.qrc">
+ <normaloff>:/images/16x16/graph-area.png</normaloff>:/images/16x16/graph-area.png</iconset>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="6">
+ <widget class="QPushButton" name="btnCancelSettings">
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="6">
+ <widget class="QPushButton" name="btnSaveSettings">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="5">
+ <spacer name="horizontalSpacer_4">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" rowspan="2" colspan="4">
+ <widget class="QFrame" name="frmOpacity">
+ <property name="frameShape">
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Plain</enum>
+ </property>
+ <property name="lineWidth">
+ <number>0</number>
+ </property>
+ <layout class="QGridLayout" name="gridLayout3">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <property name="spacing">
+ <number>-1</number>
+ </property>
+ <item row="0" column="0" colspan="4">
+ <widget class="QSlider" name="sldrOpacity">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="toolTip">
+ <string>Changes the transparency of the Bandwidth Graph</string>
+ </property>
+ <property name="minimum">
+ <number>30</number>
+ </property>
+ <property name="maximum">
+ <number>100</number>
+ </property>
+ <property name="value">
+ <number>100</number>
+ </property>
+ <property name="sliderPosition">
+ <number>100</number>
+ </property>
+ <property name="tracking">
+ <bool>false</bool>
+ </property>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="invertedAppearance">
+ <bool>false</bool>
+ </property>
+ <property name="tickPosition">
+ <enum>QSlider::NoTicks</enum>
+ </property>
+ <property name="tickInterval">
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="QLabel" name="lblPercentOpacity">
+ <property name="minimumSize">
+ <size>
+ <width>25</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="layoutDirection">
+ <enum>Qt::RightToLeft</enum>
+ </property>
+ <property name="text">
+ <string>100</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2">
+ <widget class="QLabel" name="label">
+ <property name="font">
+ <font>
+ <pointsize>10</pointsize>
+ </font>
+ </property>
+ <property name="contextMenuPolicy">
+ <enum>Qt::NoContextMenu</enum>
+ </property>
+ <property name="text">
+ <string>% Opaque</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3">
+ <spacer>
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="0">
+ <spacer name="horizontalSpacer_5">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QFrame" name="graphFrame">
+ <property name="minimumSize">
+ <size>
+ <width>128</width>
+ <height>32</height>
+ </size>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Raised</enum>
+ </property>
+ <layout class="QVBoxLayout" name="graphLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="horizontalSpacer_6">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>10000</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="2" column="0">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item>
+ <widget class="QPushButton" name="btnHistory">
+ <property name="text">
+ <string>Show History</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnSettings">
+ <property name="text">
+ <string>Show Settings</string>
+ </property>
+ <property name="checkable">
+ <bool>true</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="horizontalSpacer_3">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="btnReset">
+ <property name="text">
+ <string>Reset</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item row="1" column="1">
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>0</width>
+ <height>700</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../../vidalia/src/vidalia/res/vidalia.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/bwgraph/graphframe.js b/bwgraph/graphframe.js
new file mode 100644
index 0000000..c9e8c14
--- /dev/null
+++ b/bwgraph/graphframe.js
@@ -0,0 +1,297 @@
+importExtension("qt");
+importExtension("qt.core");
+importExtension("qt.gui");
+
+HOR_SPC = 2; /** Space between data points */
+MIN_SCALE = 10; /** 10 kB/s is the minimum scale */
+SCROLL_STEP = 4; /** Horizontal change on graph update */
+
+BACK_COLOR = new QColor(Qt.black);
+SCALE_COLOR = new QColor(Qt.green);
+GRID_COLOR = new QColor(Qt.darkGreen);
+RECV_COLOR = new QColor(Qt.cyan);
+SEND_COLOR = new QColor(Qt.yellow);
+
+FONT_SIZE = 11;
+
+SolidLine = 0;
+AreaGraph = 1;
+
+// TODO: support translations
+function tr(s) { return s; }
+
+function GraphFrame(parent)
+{
+ QFrame.call(this, parent);
+
+ /* Create Graph Frame related objects */
+ this.recvData = [];
+ this.sendData = [];
+ this.painter = new QPainter();
+ this.graphStyle = AreaGraph;
+
+ /* Initialize graph values */
+ this.recvData.unshift(0);
+ this.sendData.unshift(0);
+ this.maxPoints = this.getNumPoints();
+ this.maxPosition = 0;
+ this.showRecv = true;
+ this.showSend = true;
+ this.maxValue = MIN_SCALE;
+ this.scaleWidth = 0;
+ this.totalSend = 0;
+ this.totalRecv = 0;
+}
+
+GraphFrame.prototype = new QFrame();
+
+/** Gets the width of the desktop, which is the maximum number of points
+ * we can plot in the graph. */
+GraphFrame.prototype.getNumPoints = function()
+{
+ return this.size - this.scaleWidth;
+}
+
+/** Adds new data points to the graph. */
+GraphFrame.prototype.addPoints = function(recv, send)
+{
+ /* If maximum number of points plotted, remove oldest */
+ if (this.sendData.length == this.maxPoints) {
+ this.sendData.pop();
+ this.recvData.pop();
+ }
+
+ /* Update the displayed maximum */
+ if (this.maxPosition >= this.maxPoints) {
+ this.maxValue = MIN_SCALE;
+ for(send in this.sendData) {
+ if(send > this.maxValue)
+ this.maxValue = send;
+ }
+ for(recv in this.recvData) {
+ if(recv > this.maxValue)
+ this.maxValue = recv;
+ }
+ this.maxPosition = 0;
+ }
+
+ /* Add the points to their respective lists */
+ this.sendData.unshift(send);
+ this.recvData.unshift(recv);
+
+ /* Add to the total counters */
+ this.totalSend += send;
+ this.totalRecv += recv;
+
+ var maxUpdated = false;
+ /* Check for a new maximum value */
+ if (send > this.maxValue) {
+ this.maxValue = send;
+ maxUpdated = true;
+ }
+
+ if (recv > this.maxValue) {
+ this.maxValue = recv;
+ maxUpdated = true;
+ }
+
+ if (maxUpdated) {
+ this.maxPosition = 0;
+ } else {
+ this.maxPosition++;
+ }
+
+ this.update();
+}
+
+/** Clears the graph. */
+GraphFrame.prototype.resetGraph = function()
+{
+ this.recvData = [];
+ this.sendData = [];
+ this.recvData.unshift(0);
+ this.sendData.unshift(0);
+ this.maxValue = MIN_SCALE;
+ this.totalSend = 0;
+ this.totalRecv = 0;
+ this.update();
+}
+
+/** Toggles display of respective graph lines and counters. */
+GraphFrame.prototype.setShowCounters = function(showRecv, showSend)
+{
+ this.showRecv = showRecv;
+ this.showSend = showSend;
+}
+
+/** Returns a list of points on the bandwidth graph based on the supplied set
+ * of send or receive values. */
+GraphFrame.prototype.pointsFromData = function(list)
+{
+ var points = new Array();
+ var x = this.frameRect.width();
+ var y = this.frameRect.height();
+ var scale = (y - (y/10)) / this.maxValue;
+ var currValue = 0;
+
+ /* Translate all data points to points on the graph frame */
+ points.push(new QPointF(x, y));
+ for (var i = 0; i < list.length; i++) {
+ var item = list[i];
+ currValue = y - (item * scale);
+ if (x - SCROLL_STEP < this.scaleWidth) {
+ points.push(new QPointF(this.scaleWidth, currValue));
+ break;
+ }
+ points.push(new QPointF(x, currValue));
+ x -= SCROLL_STEP;
+ }
+ points.push(new QPointF(this.scaleWidth, y));
+ return points;
+}
+
+/** Returns the width in pixels of <b>label</b> using the current painter's
+ * font. */
+GraphFrame.prototype.labelWidth = function(label)
+{
+ var width = 0;
+ var fm = new QFontMetrics(this.font);
+
+ for (var i = 0; i < label.length; i++)
+ width += fm.charWidth(label, i);
+ return width;
+}
+
+GraphFrame.prototype.resizeEvent = function(ev)
+{
+ this.maxPoints = ev.size().width() - this.scaleWidth;
+ this.maxPoints /= SCROLL_STEP;
+ this.resize(this.parentWidget().size.width(), this.parentWidget().size.height());
+}
+
+GraphFrame.prototype.paintEvent = function(ev)
+{
+ this.painter.begin(this);
+
+ /** Filling */
+ this.painter.setRenderHint(QPainter.Antialiasing);
+ this.painter.setRenderHint(QPainter.TextAntialiasing);
+
+ /* Fill in the background */
+ this.painter.fillRect(this.frameRect, BACK_COLOR);
+
+ /** Paint Scale */
+ var label = new Array();
+ var width = new Array();
+ var top = this.frameRect.y();
+ var bottom = this.frameRect.height();
+ var scaleWidth = 0;
+ var pos = 0;
+ var markStep = this.maxValue * 0.25;
+ var paintStep = (bottom - (bottom/8)) / 4;
+
+ /* Compute each of the y-axis labels */
+ for (var i = 0; i < 4; i++) {
+ pos = bottom - ((i+1) * paintStep);
+ label[i] = (markStep*(i+1)).toFixed(2).toString() + "KB/s";
+ width[i] = this.labelWidth(label[i]);
+ scaleWidth = Math.max(scaleWidth, 2+width[i]);
+ }
+
+ /* Include a 5px margin between the y-axis and its labels */
+ this.scaleWidth = scaleWidth + 5;
+
+ /* Draw the y-axis labels and horizontal marks in their correctly scaled
+ * locations */
+ for (i = 0; i < 4; i++) {
+ pos = bottom - ((i+1) * paintStep);
+ this.painter.setPen(SCALE_COLOR);
+ this.painter.drawText(new QPointF(this.scaleWidth-width[i]-5, pos), String(label[i]));
+
+ this.painter.setPen(GRID_COLOR);
+ this.painter.drawLine(new QPointF(this.scaleWidth, pos),
+ new QPointF(this.frameRect.width(), pos));
+ }
+
+ /* Draw the y-axis */
+ this.painter.drawLine(this.scaleWidth, top, this.scaleWidth, bottom);
+
+ /**********************************************
+ * Paint data *********************************/
+ var recvPoints = [];
+ var sendPoints = [];
+
+ /* Convert the bandwidth data points to graph points */
+ recvPoints = this.pointsFromData(this.recvData);
+ sendPoints = this.pointsFromData(this.sendData);
+
+ if (this.graphStyle == AreaGraph) {
+ /* Plot the bandwidth data as area graphs */
+ if (this.showRecv)
+ {
+ var oldBrush = this.painter.brush();
+ RECV_COLOR.setAlphaF(0.6);
+ this.painter.setBrush(new QBrush(RECV_COLOR));
+ this.painter.drawPolygon(new QPolygonF(recvPoints), Qt.OddEvenFill);
+ this.painter.setBrush(oldBrush);
+ }
+ if (this.showSend)
+ {
+ var oldBrush = this.painter.brush();
+ SEND_COLOR.setAlphaF(0.4);
+ this.painter.setBrush(new QBrush(SEND_COLOR));
+ this.painter.drawPolygon(new QPolygonF(sendPoints), Qt.OddEvenFill);
+ this.painter.setBrush(oldBrush);
+ }
+ }
+
+ /* Plot the bandwidth as solid lines. If the graph style is currently an
+ * area graph, we end up outlining the integrals. */
+ if (this.showRecv)
+ {
+ var oldPen = this.painter.pen();
+ this.painter.setPen(RECV_COLOR);
+ this.painter.drawPolyline(new QPolygonF(recvPoints));
+ this.painter.setPen(oldPen);
+ }
+ if (this.showSend)
+ {
+ var oldPen = this.painter.pen();
+ this.painter.setPen(SEND_COLOR);
+ this.painter.drawPolyline(new QPolygonF(sendPoints));
+ this.painter.setPen(oldPen);
+ }
+
+ /************************************************
+ * Paint totals *********************************/
+ var x = this.scaleWidth + FONT_SIZE;
+ var y = 0;
+ var rowHeight = FONT_SIZE;
+
+ /* On Mac, we don't need vertical spacing between the text rows. */
+ // TODO: see how to use this in this case since we don't have preproc
+ rowHeight += 5;
+
+ /* If total received is selected */
+ if (this.showRecv) {
+ y = rowHeight;
+ this.painter.setPen(RECV_COLOR);
+ var total = Math.floor(this.totalRecv*100) / 100;
+ var count = Math.floor(this.recvData[0]*100) / 100;
+ this.painter.drawText(new QPoint(x, y),
+ tr("Recv:") + " " + total +
+ " (" + count + "KB/s)");
+ }
+
+ /* If total sent is selected */
+ if (this.showSend) {
+ y += rowHeight;
+ this.painter.setPen(SEND_COLOR);
+ var total = Math.floor(this.totalSend*100) / 100;
+ var count = Math.floor(this.sendData[0]*100) / 100;
+ this.painter.drawText(new QPoint(x, y),
+ tr("Sent:") + " " + total +
+ " (" + count + "KB/s)");
+ }
+ this.painter.end();
+}
diff --git a/bwgraph/info.xml b/bwgraph/info.xml
new file mode 100644
index 0000000..7d54654
--- /dev/null
+++ b/bwgraph/info.xml
@@ -0,0 +1,11 @@
+<VidaliaPlugin>
+ <name>Bandwidth Graph</name>
+ <date>11/06/2012</date>
+ <author>chiiph</author>
+ <type persistent="true" gui="true" />
+ <files>
+ <file>graphframe.js</file>
+ <file>bwgraph.js</file>
+ </files>
+ <namespace>bwgraph</namespace>
+</VidaliaPlugin>
1
0
commit 29dccd1f44b895d674079d085207e4e71b43beac
Author: Arturo Filastò <art(a)torproject.org>
Date: Sat Jul 21 01:30:03 2012 +0200
s/b0wser/daphn3/i
because greek mythology is cooler than video games!
---
ooni/plugins/b0wser.py | 100 ----------------
ooni/plugins/daphn3.py | 100 ++++++++++++++++
ooni/protocols/b0wser.py | 284 ----------------------------------------------
ooni/protocols/daphn3.py | 284 ++++++++++++++++++++++++++++++++++++++++++++++
oonib/b0wser.py | 33 ------
oonib/daphn3.py | 33 ++++++
oonib/oonibackend.py | 6 +-
7 files changed, 420 insertions(+), 420 deletions(-)
diff --git a/ooni/plugins/b0wser.py b/ooni/plugins/b0wser.py
deleted file mode 100644
index 3121378..0000000
--- a/ooni/plugins/b0wser.py
+++ /dev/null
@@ -1,100 +0,0 @@
-"""
-This is a self genrated test created by scaffolding.py.
-you will need to fill it up with all your necessities.
-Safe hacking :).
-"""
-from zope.interface import implements
-from twisted.python import usage
-from twisted.plugin import IPlugin
-from twisted.internet import protocol, endpoints
-
-from ooni.plugoo.tests import ITest, OONITest
-from ooni.plugoo.assets import Asset
-from ooni.protocols import b0wser
-from ooni.utils import log
-
-class B0wserClientProtocol(b0wser.B0wserProtocol):
- def connectionMade(self):
- self.next_state()
-
- def connectionLost(self, reason):
- print "LOST!"
-
-class B0wserClientFactory(protocol.ClientFactory):
- protocol = B0wserClientProtocol
- mutator = None
- steps = None
-
- def buildProtocol(self, addr):
- p = self.protocol()
- p.factory = self
- if self.steps:
- p.steps = self.steps
-
- if not self.mutator:
- self.mutator = b0wser.Mutator(p.steps)
- p.mutator = self.mutator
- else:
- print "Moving on to next mutation"
- self.mutator.next_mutation()
- return p
-
- def clientConnectionFailed(self, reason):
- print "We failed connecting the the OONIB"
- print "Cannot perform test. Perhaps it got blocked?"
- print "Please report this to tor-assistants(a)torproject.org"
-
- def clientConnectionLost(self, reason):
- print "Connection Lost."
-
-class b0wserArgs(usage.Options):
- optParameters = [['pcap', 'f', None, 'PCAP file to take as input'],
- ['host', 'h', None, 'Target Hostname'],
- ['port', 'p', None, 'Target port number'],
- ['resume', 'r', 0, 'Resume at this index']]
-
-class b0wserTest(OONITest):
- implements(IPlugin, ITest)
-
- shortName = "b0wser"
- description = "b0wser"
- requirements = None
- options = b0wserArgs
- blocking = False
-
- local_options = None
-
- steps = None
- def initialize(self):
- if not self.local_options:
- return
- #pass
- self.factory = B0wserClientFactory()
- self.steps = b0wser.get_b0wser_dictionary_from_pcap(self.local_options['pcap'])
-
- def control(self, exp_res, args):
- mutation = self.factory.mutator.get_mutation(0)
- return {'mutation_number': args['mutation'], 'value': mutation}
-
- def experiment(self, args):
- log.msg("Doing mutation %s" % args['mutation'])
- self.factory.steps = self.steps
- host = self.local_options['host']
- port = int(self.local_options['port'])
- log.msg("Connecting to %s:%s" % (host, port))
- endpoint = endpoints.TCP4ClientEndpoint(self.reactor, host, port)
- return endpoint.connect(self.factory)
- #return endpoint.connect(B0wserClientFactory)
-
- def load_assets(self):
- if not self.steps:
- print "No asset!"
- return {}
- mutations = 0
- for x in self.steps:
- mutations += len(x['data'])
- return {'mutation': range(mutations)}
-
-# We need to instantiate it otherwise getPlugins does not detect it
-# XXX Find a way to load plugins without instantiating them.
-b0wsertest = b0wserTest(None, None, None)
diff --git a/ooni/plugins/daphn3.py b/ooni/plugins/daphn3.py
new file mode 100644
index 0000000..6dd9da2
--- /dev/null
+++ b/ooni/plugins/daphn3.py
@@ -0,0 +1,100 @@
+"""
+This is a self genrated test created by scaffolding.py.
+you will need to fill it up with all your necessities.
+Safe hacking :).
+"""
+from zope.interface import implements
+from twisted.python import usage
+from twisted.plugin import IPlugin
+from twisted.internet import protocol, endpoints
+
+from ooni.plugoo.tests import ITest, OONITest
+from ooni.plugoo.assets import Asset
+from ooni.protocols import daphn3
+from ooni.utils import log
+
+class Daphn3ClientProtocol(daphn3.Daphn3Protocol):
+ def connectionMade(self):
+ self.next_state()
+
+ def connectionLost(self, reason):
+ print "LOST!"
+
+class Daphn3ClientFactory(protocol.ClientFactory):
+ protocol = Daphn3ClientProtocol
+ mutator = None
+ steps = None
+
+ def buildProtocol(self, addr):
+ p = self.protocol()
+ p.factory = self
+ if self.steps:
+ p.steps = self.steps
+
+ if not self.mutator:
+ self.mutator = daphn3.Mutator(p.steps)
+ p.mutator = self.mutator
+ else:
+ print "Moving on to next mutation"
+ self.mutator.next_mutation()
+ return p
+
+ def clientConnectionFailed(self, reason):
+ print "We failed connecting the the OONIB"
+ print "Cannot perform test. Perhaps it got blocked?"
+ print "Please report this to tor-assistants(a)torproject.org"
+
+ def clientConnectionLost(self, reason):
+ print "Connection Lost."
+
+class daphn3Args(usage.Options):
+ optParameters = [['pcap', 'f', None, 'PCAP file to take as input'],
+ ['host', 'h', None, 'Target Hostname'],
+ ['port', 'p', None, 'Target port number'],
+ ['resume', 'r', 0, 'Resume at this index']]
+
+class daphn3Test(OONITest):
+ implements(IPlugin, ITest)
+
+ shortName = "daphn3"
+ description = "daphn3"
+ requirements = None
+ options = daphn3Args
+ blocking = False
+
+ local_options = None
+
+ steps = None
+ def initialize(self):
+ if not self.local_options:
+ return
+ #pass
+ self.factory = Daphn3ClientFactory()
+ self.steps = daphn3.get_daphn3_dictionary_from_pcap(self.local_options['pcap'])
+
+ def control(self, exp_res, args):
+ mutation = self.factory.mutator.get_mutation(0)
+ return {'mutation_number': args['mutation'], 'value': mutation}
+
+ def experiment(self, args):
+ log.msg("Doing mutation %s" % args['mutation'])
+ self.factory.steps = self.steps
+ host = self.local_options['host']
+ port = int(self.local_options['port'])
+ log.msg("Connecting to %s:%s" % (host, port))
+ endpoint = endpoints.TCP4ClientEndpoint(self.reactor, host, port)
+ return endpoint.connect(self.factory)
+ #return endpoint.connect(Daphn3ClientFactory)
+
+ def load_assets(self):
+ if not self.steps:
+ print "No asset!"
+ return {}
+ mutations = 0
+ for x in self.steps:
+ mutations += len(x['data'])
+ return {'mutation': range(mutations)}
+
+# We need to instantiate it otherwise getPlugins does not detect it
+# XXX Find a way to load plugins without instantiating them.
+daphn3test = daphn3Test(None, None, None)
diff --git a/ooni/protocols/b0wser.py b/ooni/protocols/b0wser.py
deleted file mode 100644
index 5d55c94..0000000
--- a/ooni/protocols/b0wser.py
+++ /dev/null
@@ -1,284 +0,0 @@
-from twisted.internet import protocol, defer
-from twisted.internet.error import ConnectionDone
-
-from ooni.utils import log
-from ooni.plugoo import reports
-
-import sys
-from scapy.all import *
-import yaml
-
-def get_b0wser_dictionary_from_pcap(filename):
- """
- @param filename: Filesystem path to the pcap.
-
- Returns:
- [{"sender": "client", "data": "\x17\x52\x15"}, {"sender": "server", "data": "\x17\x15\x13"}]
- """
- packets = rdpcap(filename)
-
- checking_first_packet = True
- client_ip_addr = None
- server_ip_addr = None
-
- ssl_packets = []
- messages = []
-
- """
- pcap assumptions:
-
- pcap only contains packets exchanged between a Tor client and a Tor server.
- (This assumption makes sure that there are only two IP addresses in the
- pcap file)
-
- The first packet of the pcap is sent from the client to the server. (This
- assumption is used to get the IP address of the client.)
-
- All captured packets are TLS packets: that is TCP session
- establishment/teardown packets should be filtered out (no SYN/SYN+ACK)
- """
-
- """Minimally validate the pcap and also find out what's the client
- and server IP addresses."""
- for packet in packets:
- if checking_first_packet:
- client_ip_addr = packet[IP].src
- checking_first_packet = False
- else:
- if packet[IP].src != client_ip_addr:
- server_ip_addr = packet[IP].src
-
- try:
- if (packet[Raw]):
- ssl_packets.append(packet)
- except IndexError:
- pass
-
- """Form our list."""
- for packet in ssl_packets:
- if packet[IP].src == client_ip_addr:
- messages.append({"sender": "client", "data": str(packet[Raw])})
- elif packet[IP].src == server_ip_addr:
- messages.append({"sender": "server", "data": str(packet[Raw])})
- else:
- raise("Detected third IP address! pcap is corrupted.")
-
- return messages
-
-class Mutator:
- idx = 0
- step = 0
-
- waiting = False
- waiting_step = 0
-
- def __init__(self, steps):
- """
- @param steps: array of dicts containing as keys data and wait. Data is
- the content of the ith packet to be sent and wait is how
- much we should wait before mutating the packet of the
- next step.
- """
- self.steps = steps
-
- def _mutate(self, data, idx):
- """
- Mutate the idx bytes by increasing it's value by one
-
- @param data: the data to be mutated.
-
- @param idx: what byte should be mutated.
- """
- print "idx: %s, data: %s" % (idx, data)
- ret = data[:idx]
- ret += chr(ord(data[idx]) + 1)
- ret += data[idx+1:]
- return ret
-
- def state(self):
- """
- Return the current mutation state. As in what bytes are being mutated.
-
- Returns a dict containg the packet index and the step number.
- """
- print "[Mutator.state()] Giving out my internal state."
- current_state = {'idx': self.idx, 'step': self.step}
- return current_state
-
- def next_mutation(self):
- """
- Increases by one the mutation state.
-
- ex. (* is the mutation state, i.e. the byte to be mutated)
- before [___*] [____]
- step1 step2
- after [____] [*___]
-
- Should be called every time you need to proceed onto the next mutation.
- It changes the internal state of the mutator to that of the next
- mutatation.
-
- returns True if another mutation is available.
- returns False if all the possible mutations have been done.
- """
- if (self.step + 1) > len(self.steps):
- # Hack to stop once we have gone through all the steps
- print "[Mutator.next_mutation()] I believe I have gone over all steps"
- print " Stopping!"
- self.waiting = True
- return False
-
- self.idx += 1
- current_idx = self.idx
- current_step = self.step
- current_data = self.steps[current_step]['data']
- try:
- data_to_receive = len(self.steps[current_step +1 ]['data'])
- print "[Mutator.next_mutation()] Managed to receive some data."
- except:
- print "[Mutator.next_mutation()] No more data to receive."
-
- if self.waiting and self.waiting_step == data_to_receive:
- print "[Mutator.next_mutation()] I am no longer waiting"
- log.debug("I am no longer waiting.")
- self.waiting = False
- self.waiting_step = 0
- self.idx = 0
-
- elif self.waiting:
- print "[Mutator.next_mutation()] Waiting some more."
- log.debug("Waiting some more.")
- self.waiting_step += 1
-
- elif current_idx >= len(current_data):
- print "[Mutator.next_mutation()] Entering waiting mode."
- log.debug("Entering waiting mode.")
- self.step += 1
- self.idx = 0
- self.waiting = True
- log.debug("current index %s" % current_idx)
- log.debug("current data %s" % len(current_data))
- return True
-
- def get_mutation(self, step):
- """
- Returns the current packet to be sent to the wire.
- If no mutation is necessary it will return the plain data.
- Should be called when you are interested in obtaining the data to be
- sent for the selected state.
-
- @param step: the current step you want the mutation for
-
- returns the mutated packet for the specified step.
- """
- if step != self.step or self.waiting:
- log.debug("[Mutator.get_mutation()] I am not going to do anything :)")
- return self.steps[step]['data']
-
- data = self.steps[step]['data']
- print "Mutating %s with idx %s" % (data, self.idx)
- return self._mutate(data, self.idx)
-
-class B0wserProtocol(protocol.Protocol):
- """
- This implements the B0wser protocol for the server side.
- It gets instanced once for every client that connects to the oonib.
- For every instance of protocol there is only 1 mutation.
- Once the last step is reached the connection is closed on the serverside.
- """
- steps = []
- mutator = None
-
- role = 'client'
- state = 0
- total_states = len(steps) - 1
- received_data = 0
- to_receive_data = 0
- report = reports.Report('b0wser', 'b0wser.yamlooni')
-
- def next_state(self):
- """
- This is called once I have completed one step of the protocol and need
- to proceed to the next step.
- """
- if not self.mutator:
- print "[B0wserProtocol.next_state] No mutator. There is no point to stay on this earth."
- self.transport.loseConnection()
- return
- if self.role is self.steps[self.state]['sender']:
- print "[B0wserProtocol.next_state] I am a sender"
- data = self.mutator.get_mutation(self.state)
- self.transport.write(data)
- self.to_receive_data = 0
- else:
- print "[B0wserProtocol.next_state] I am a receiver"
- self.to_receive_data = len(self.steps[self.state]['data'])
-
- self.state += 1
- self.received_data = 0
-
- def dataReceived(self, data):
- """
- This is called every time some data is received. I transition to the
- next step once the amount of data that I expect to receive is received.
-
- @param data: the data that has been sent by the client.
- """
- if not self.mutator:
- print "I don't have a mutator. My life means nothing."
- self.transport.loseConnection()
- return
- if len(self.steps) <= self.state:
- print "I have reached the end of the state machine"
- print "Censorship fingerprint bruteforced!"
- report = {'mutator_state': self.mutator.state()}
- self.report(report)
- self.transport.loseConnection()
- return
-
- self.received_data += len(data)
- if self.received_data >= self.to_receive_data:
- print "Moving to next state %s" % self.state
- self.next_state()
-
- def censorship_detected(self, report):
- """
- I have detected the possible presence of censorship we need to write a
- report on it.
-
- @param report: a dict containing the report to be written. Must contain
- the keys 'reason', 'proto_state' and 'mutator_state'.
- The reason is the reason for which the connection was
- closed. The proto_state is the current state of the
- protocol instance and mutator_state is what was being
- mutated.
- """
- print "The connection was closed because of %s" % report['reason']
- print "State %s, Mutator %s" % (report['proto_state'],
- report['mutator_state'])
- self.mutator.next_mutation()
-
-
-
- def connectionLost(self, reason):
- """
- The connection was closed. This may be because of a legittimate reason
- or it may be because of a censorship event.
- """
- if not self.mutator:
- print "Terminated because of little interest in life."
- return
- report = {'reason': reason, 'proto_state': self.state,
- 'trigger': None, 'mutator_state': self.mutator.state()}
-
- if self.state < self.total_states:
- report['trigger'] = 'did not finish state walk'
- self.censorship_detected(report)
-
- if reason.check(ConnectionDone):
- print "Connection closed cleanly"
- else:
- report['trigger'] = 'unclean connection closure'
- self.censorship_detected(report)
-
-
diff --git a/ooni/protocols/daphn3.py b/ooni/protocols/daphn3.py
new file mode 100644
index 0000000..d8290e6
--- /dev/null
+++ b/ooni/protocols/daphn3.py
@@ -0,0 +1,284 @@
+from twisted.internet import protocol, defer
+from twisted.internet.error import ConnectionDone
+
+from ooni.utils import log
+from ooni.plugoo import reports
+
+import sys
+from scapy.all import *
+import yaml
+
+def get_daphn3_dictionary_from_pcap(filename):
+ """
+ @param filename: Filesystem path to the pcap.
+
+ Returns:
+ [{"sender": "client", "data": "\x17\x52\x15"}, {"sender": "server", "data": "\x17\x15\x13"}]
+ """
+ packets = rdpcap(filename)
+
+ checking_first_packet = True
+ client_ip_addr = None
+ server_ip_addr = None
+
+ ssl_packets = []
+ messages = []
+
+ """
+ pcap assumptions:
+
+ pcap only contains packets exchanged between a Tor client and a Tor server.
+ (This assumption makes sure that there are only two IP addresses in the
+ pcap file)
+
+ The first packet of the pcap is sent from the client to the server. (This
+ assumption is used to get the IP address of the client.)
+
+ All captured packets are TLS packets: that is TCP session
+ establishment/teardown packets should be filtered out (no SYN/SYN+ACK)
+ """
+
+ """Minimally validate the pcap and also find out what's the client
+ and server IP addresses."""
+ for packet in packets:
+ if checking_first_packet:
+ client_ip_addr = packet[IP].src
+ checking_first_packet = False
+ else:
+ if packet[IP].src != client_ip_addr:
+ server_ip_addr = packet[IP].src
+
+ try:
+ if (packet[Raw]):
+ ssl_packets.append(packet)
+ except IndexError:
+ pass
+
+ """Form our list."""
+ for packet in ssl_packets:
+ if packet[IP].src == client_ip_addr:
+ messages.append({"sender": "client", "data": str(packet[Raw])})
+ elif packet[IP].src == server_ip_addr:
+ messages.append({"sender": "server", "data": str(packet[Raw])})
+ else:
+ raise("Detected third IP address! pcap is corrupted.")
+
+ return messages
+
+class Mutator:
+ idx = 0
+ step = 0
+
+ waiting = False
+ waiting_step = 0
+
+ def __init__(self, steps):
+ """
+ @param steps: array of dicts containing as keys data and wait. Data is
+ the content of the ith packet to be sent and wait is how
+ much we should wait before mutating the packet of the
+ next step.
+ """
+ self.steps = steps
+
+ def _mutate(self, data, idx):
+ """
+ Mutate the idx bytes by increasing it's value by one
+
+ @param data: the data to be mutated.
+
+ @param idx: what byte should be mutated.
+ """
+ print "idx: %s, data: %s" % (idx, data)
+ ret = data[:idx]
+ ret += chr(ord(data[idx]) + 1)
+ ret += data[idx+1:]
+ return ret
+
+ def state(self):
+ """
+ Return the current mutation state. As in what bytes are being mutated.
+
+ Returns a dict containg the packet index and the step number.
+ """
+ print "[Mutator.state()] Giving out my internal state."
+ current_state = {'idx': self.idx, 'step': self.step}
+ return current_state
+
+ def next_mutation(self):
+ """
+ Increases by one the mutation state.
+
+ ex. (* is the mutation state, i.e. the byte to be mutated)
+ before [___*] [____]
+ step1 step2
+ after [____] [*___]
+
+ Should be called every time you need to proceed onto the next mutation.
+ It changes the internal state of the mutator to that of the next
+ mutatation.
+
+ returns True if another mutation is available.
+ returns False if all the possible mutations have been done.
+ """
+ if (self.step + 1) > len(self.steps):
+ # Hack to stop once we have gone through all the steps
+ print "[Mutator.next_mutation()] I believe I have gone over all steps"
+ print " Stopping!"
+ self.waiting = True
+ return False
+
+ self.idx += 1
+ current_idx = self.idx
+ current_step = self.step
+ current_data = self.steps[current_step]['data']
+ try:
+ data_to_receive = len(self.steps[current_step +1 ]['data'])
+ print "[Mutator.next_mutation()] Managed to receive some data."
+ except:
+ print "[Mutator.next_mutation()] No more data to receive."
+
+ if self.waiting and self.waiting_step == data_to_receive:
+ print "[Mutator.next_mutation()] I am no longer waiting"
+ log.debug("I am no longer waiting.")
+ self.waiting = False
+ self.waiting_step = 0
+ self.idx = 0
+
+ elif self.waiting:
+ print "[Mutator.next_mutation()] Waiting some more."
+ log.debug("Waiting some more.")
+ self.waiting_step += 1
+
+ elif current_idx >= len(current_data):
+ print "[Mutator.next_mutation()] Entering waiting mode."
+ log.debug("Entering waiting mode.")
+ self.step += 1
+ self.idx = 0
+ self.waiting = True
+ log.debug("current index %s" % current_idx)
+ log.debug("current data %s" % len(current_data))
+ return True
+
+ def get_mutation(self, step):
+ """
+ Returns the current packet to be sent to the wire.
+ If no mutation is necessary it will return the plain data.
+ Should be called when you are interested in obtaining the data to be
+ sent for the selected state.
+
+ @param step: the current step you want the mutation for
+
+ returns the mutated packet for the specified step.
+ """
+ if step != self.step or self.waiting:
+ log.debug("[Mutator.get_mutation()] I am not going to do anything :)")
+ return self.steps[step]['data']
+
+ data = self.steps[step]['data']
+ print "Mutating %s with idx %s" % (data, self.idx)
+ return self._mutate(data, self.idx)
+
+class Daphn3Protocol(protocol.Protocol):
+ """
+ This implements the Daphn3 protocol for the server side.
+ It gets instanced once for every client that connects to the oonib.
+ For every instance of protocol there is only 1 mutation.
+ Once the last step is reached the connection is closed on the serverside.
+ """
+ steps = []
+ mutator = None
+
+ role = 'client'
+ state = 0
+ total_states = len(steps) - 1
+ received_data = 0
+ to_receive_data = 0
+ report = reports.Report('daphn3', 'daphn3.yamlooni')
+
+ def next_state(self):
+ """
+ This is called once I have completed one step of the protocol and need
+ to proceed to the next step.
+ """
+ if not self.mutator:
+ print "[Daphn3Protocol.next_state] No mutator. There is no point to stay on this earth."
+ self.transport.loseConnection()
+ return
+ if self.role is self.steps[self.state]['sender']:
+ print "[Daphn3Protocol.next_state] I am a sender"
+ data = self.mutator.get_mutation(self.state)
+ self.transport.write(data)
+ self.to_receive_data = 0
+ else:
+ print "[Daphn3Protocol.next_state] I am a receiver"
+ self.to_receive_data = len(self.steps[self.state]['data'])
+
+ self.state += 1
+ self.received_data = 0
+
+ def dataReceived(self, data):
+ """
+ This is called every time some data is received. I transition to the
+ next step once the amount of data that I expect to receive is received.
+
+ @param data: the data that has been sent by the client.
+ """
+ if not self.mutator:
+ print "I don't have a mutator. My life means nothing."
+ self.transport.loseConnection()
+ return
+ if len(self.steps) <= self.state:
+ print "I have reached the end of the state machine"
+ print "Censorship fingerprint bruteforced!"
+ report = {'mutator_state': self.mutator.state()}
+ self.report(report)
+ self.transport.loseConnection()
+ return
+
+ self.received_data += len(data)
+ if self.received_data >= self.to_receive_data:
+ print "Moving to next state %s" % self.state
+ self.next_state()
+
+ def censorship_detected(self, report):
+ """
+ I have detected the possible presence of censorship we need to write a
+ report on it.
+
+ @param report: a dict containing the report to be written. Must contain
+ the keys 'reason', 'proto_state' and 'mutator_state'.
+ The reason is the reason for which the connection was
+ closed. The proto_state is the current state of the
+ protocol instance and mutator_state is what was being
+ mutated.
+ """
+ print "The connection was closed because of %s" % report['reason']
+ print "State %s, Mutator %s" % (report['proto_state'],
+ report['mutator_state'])
+ self.mutator.next_mutation()
+
+
+
+ def connectionLost(self, reason):
+ """
+ The connection was closed. This may be because of a legittimate reason
+ or it may be because of a censorship event.
+ """
+ if not self.mutator:
+ print "Terminated because of little interest in life."
+ return
+ report = {'reason': reason, 'proto_state': self.state,
+ 'trigger': None, 'mutator_state': self.mutator.state()}
+
+ if self.state < self.total_states:
+ report['trigger'] = 'did not finish state walk'
+ self.censorship_detected(report)
+
+ if reason.check(ConnectionDone):
+ print "Connection closed cleanly"
+ else:
+ report['trigger'] = 'unclean connection closure'
+ self.censorship_detected(report)
+
+
diff --git a/oonib/b0wser.py b/oonib/b0wser.py
deleted file mode 100644
index 4500075..0000000
--- a/oonib/b0wser.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from twisted.internet import protocol
-from twisted.internet.error import ConnectionDone
-
-from ooni.plugoo import reports
-from ooni.protocols.b0wser import Mutator, B0wserProtocol
-
-class B0wserServer(protocol.ServerFactory):
- """
- This is the main class that deals with the b0wser server side component.
- We keep track of global state of every client here.
- Every client is identified by their IP address and the state of mutation is
- stored by using their IP address as a key. This may lead to some bugs if
- two different clients are sharing the same IP, but hopefully the
- probability of such thing is not that likely.
- """
- protocol = B0wserProtocol
- mutations = {}
- def buildProtocol(self, addr):
- p = self.protocol()
- p.factory = self
-
- if addr.host not in self.mutations:
- self.mutations[addr.host] = Mutator(p.steps)
- else:
- print "Moving on to next mutation"
- if not self.mutations[addr.host].next_mutation():
- self.mutations.pop(addr.host)
- try:
- p.mutator = self.mutations[addr.host]
- except:
- pass
- return p
-
diff --git a/oonib/daphn3.py b/oonib/daphn3.py
new file mode 100644
index 0000000..22aef49
--- /dev/null
+++ b/oonib/daphn3.py
@@ -0,0 +1,33 @@
+from twisted.internet import protocol
+from twisted.internet.error import ConnectionDone
+
+from ooni.plugoo import reports
+from ooni.protocols.daphn3 import Mutator, daphn3Protocol
+
+class daphn3Server(protocol.ServerFactory):
+ """
+ This is the main class that deals with the daphn3 server side component.
+ We keep track of global state of every client here.
+ Every client is identified by their IP address and the state of mutation is
+ stored by using their IP address as a key. This may lead to some bugs if
+ two different clients are sharing the same IP, but hopefully the
+ probability of such thing is not that likely.
+ """
+ protocol = daphn3Protocol
+ mutations = {}
+ def buildProtocol(self, addr):
+ p = self.protocol()
+ p.factory = self
+
+ if addr.host not in self.mutations:
+ self.mutations[addr.host] = Mutator(p.steps)
+ else:
+ print "Moving on to next mutation"
+ if not self.mutations[addr.host].next_mutation():
+ self.mutations.pop(addr.host)
+ try:
+ p.mutator = self.mutations[addr.host]
+ except:
+ pass
+ return p
+
diff --git a/oonib/oonibackend.py b/oonib/oonibackend.py
index 4ae275e..22a8728 100755
--- a/oonib/oonibackend.py
+++ b/oonib/oonibackend.py
@@ -18,7 +18,7 @@ from twisted.names import dns
from oonib.httpbackend import HTTPBackend
from oonib.dnsbackend import ProxyDNSServer
-from oonib.b0wser import B0wserServer
+from oonib.daphn3 import Daphn3Server
# This tells twisted to set the
server.version = "Apache"
@@ -34,5 +34,5 @@ UDPFactory = dns.DNSDatagramProtocol(TCPDNSServer)
internet.UDPServer(5354, UDPFactory).setServiceParent(serviceCollection)
# Start the ooni backend thing
-b0wser = B0wserServer()
-internet.TCPServer(9666, b0wser).setServiceParent(serviceCollection)
+daphn3 = Daphn3Server()
+internet.TCPServer(9666, daphn3).setServiceParent(serviceCollection)
1
0

[stegotorus/master] More size_t values must be cast to unsigned long
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 4195993aa3e15ebfc895299d5b8342971067ec12
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Thu May 3 10:40:21 2012 -0700
More size_t values must be cast to unsigned long
---
src/network.cc | 6 +++---
1 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/network.cc b/src/network.cc
index 6039df0..f436ef4 100644
--- a/src/network.cc
+++ b/src/network.cc
@@ -378,10 +378,10 @@ downstream_event_cb(struct bufferevent *bev, short what, void *arg)
{
conn_t *conn = (conn_t *)arg;
- log_debug(conn, "what=%04hx enabled=%x inbound=%ld outbound=%ld",
+ log_debug(conn, "what=%04hx enabled=%x inbound=%lu outbound=%lu",
what, bufferevent_get_enabled(bev),
- evbuffer_get_length(bufferevent_get_input(bev)),
- evbuffer_get_length(bufferevent_get_output(bev)));
+ (unsigned long)evbuffer_get_length(bufferevent_get_input(bev)),
+ (unsigned long)evbuffer_get_length(bufferevent_get_output(bev)));
if (what & (BEV_EVENT_ERROR|BEV_EVENT_EOF|BEV_EVENT_TIMEOUT)) {
if (what & BEV_EVENT_ERROR)
1
0
commit 6161bb51a042e5ab6b3f4bdf929258307b86e759
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 14:09:54 2012 -0700
Fix compile errors with gcc 4.7
---
src/steg/jsSteg.cc | 2 +-
src/test/tinytest_macros.h | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/steg/jsSteg.cc b/src/steg/jsSteg.cc
index 6ff0b89..dbe4431 100644
--- a/src/steg/jsSteg.cc
+++ b/src/steg/jsSteg.cc
@@ -351,7 +351,7 @@ int encodeHTTPBody(char *data, char *jTemplate, char *jData,
char *jsStart, *jsEnd;
int skip;
int scriptLen;
- int fin;
+ int fin = 0;
unsigned int dlen2 = dlen;
dp = data;
jtp = jTemplate;
diff --git a/src/test/tinytest_macros.h b/src/test/tinytest_macros.h
index 00d8732..5dd2742 100644
--- a/src/test/tinytest_macros.h
+++ b/src/test/tinytest_macros.h
@@ -112,7 +112,7 @@
setup_block; \
_print2 = _print; \
TT_DECLARE(_tt_status?" OK":"FAIL", \
- ("assert(%s): "printf_fmt" vs "printf_fmt, \
+ ("assert(%s): " printf_fmt " vs " printf_fmt,\
str_test, _print1, _print2)); \
_print = _print1; \
cleanup_block; \
1
0

[stegotorus/master] Have configure activate extended C library features and large file support. Detect whether 'ranlib' is unnecessary.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 491d09efb9e90c8762954f68e37efb7f42f38a16
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 14:15:10 2012 -0700
Have configure activate extended C library features and large file support. Detect whether 'ranlib' is unnecessary.
---
configure.ac | 22 +++++++++----
m4/ranlib.m4 | 69 ++++++++++++++++++++++++++++++++++++++++
m4/system_extensions.m4 | 81 +++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 165 insertions(+), 7 deletions(-)
diff --git a/configure.ac b/configure.ac
index 647879a..6dc4fe3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -9,10 +9,22 @@ AC_LANG([C++])
AM_INIT_AUTOMAKE([foreign nostdinc silent-rules subdir-objects])
AM_MAINTAINER_MODE([enable])
-### Programs ###
+### Compiler and language features ###
+AC_PROG_CC
AC_PROG_CXX
-AC_PROG_RANLIB
+AC_PROG_CXXCPP
+
+AX_SYS_EXTENSIONS
+AC_SYS_LARGEFILE
+
+AX_CXXFLAGS_STDCXX_11([ext])
+AX_CXX_DELETE_METHOD
+AX_CXX_STATIC_ASSERT
+
+### Programs ###
+
+AX_PROG_RANLIB
PKG_PROG_PKG_CONFIG
# We need python 2.7 for TestLoader.discover().
@@ -60,14 +72,10 @@ AC_SUBST(lib_CPPFLAGS)
AX_LIB_WINSOCK2
LIBS="$LIBS $ws32_LIBS"
-### Language features ###
+### System features ###
AC_CHECK_HEADERS([execinfo.h],,,[/**/])
-AX_CXXFLAGS_STDCXX_11([ext])
-AX_CXX_DELETE_METHOD
-AX_CXX_STATIC_ASSERT
-
### Output ###
AC_CONFIG_FILES([Makefile])
diff --git a/m4/ranlib.m4 b/m4/ranlib.m4
new file mode 100644
index 0000000..ce4fe33
--- /dev/null
+++ b/m4/ranlib.m4
@@ -0,0 +1,69 @@
+# SYNOPSIS
+#
+# AX_PROG_RANLIB
+#
+# DESCRIPTION
+#
+# In addition to everything AC_PROG_RANLIB does, determine whether it is
+# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
+# the case on most modern systems), reset the RANLIB variable to ':'.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# 'ranlib' may be needed to make it possible for objects that occur
+# later in an archive library to refer to symbols defined by objects
+# earlier in the archive. Therefore, the testing strategy is to
+# compile three small files where A refers to B refers to C, put C and
+# B in an archive *in that order*, and then see if we can link A
+# against the archive.
+
+AC_DEFUN([AX_PROG_RANLIB],
+[AC_CHECK_TOOL([AR], [ar])
+AC_CHECK_TOOL([RANLIB], [ranlib], [:])
+if test x$RANLIB != x:; then
+ AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
+ [AC_LANG_PUSH([C])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int B(void);
+ int main(void) { return B(); }
+ ]])],
+ [cp conftest.$ac_objext conftA.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file A])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int C(void);
+ int B(void) { return C(); }
+ ]])],
+ [cp conftest.$ac_objext conftB.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file B])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ int C(void) { return 0; }
+ ]])],
+ [cp conftest.$ac_objext conftC.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file C])])
+
+ dnl There is no standard macro for creating an archive.
+ _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
+ AC_MSG_ERROR([failed to create test archive])
+
+ dnl There's no good way to make AC_LINK_IFELSE do what we need.
+ AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=no],
+ [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=yes],
+ [AC_MSG_ERROR([test link failed with and without ranlib])])])
+
+ rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
+ AC_LANG_POP([C])
+ ])
+ if test $ac_cv_prog_RANLIB_necessary = no; then
+ RANLIB=:
+ fi
+fi
+])
diff --git a/m4/system_extensions.m4 b/m4/system_extensions.m4
new file mode 100644
index 0000000..46b2f9e
--- /dev/null
+++ b/m4/system_extensions.m4
@@ -0,0 +1,81 @@
+# SYNOPSIS
+#
+# AX_SYS_EXTENSIONS
+#
+# DESCRIPTION
+#
+# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
+# does not trigger AC_CHECK_HEADER's backward compatibility mode;
+# does not make use of AC_INCLUDES_DEFAULT;
+# does not define _MINIX.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+#
+# Remember that #undef in AH_VERBATIM gets replaced with #define by
+# AC_DEFINE. The goal here is to define all known feature-enabling
+# macros, then, if reports of conflicts are made, disable macros that
+# cause problems on some platforms (such as __EXTENSIONS__).
+AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
+[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
+
+ AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
+ if test "$MINIX" = yes; then
+ AC_DEFINE([_POSIX_SOURCE], [1],
+ [Define to 1 if you need to in order for `stat' and other
+ things to work.])
+ AC_DEFINE([_POSIX_1_SOURCE], [2],
+ [Define to 2 if the system does not provide POSIX.1 features
+ except with this defined.])
+ fi
+
+dnl Use a different key than __EXTENSIONS__, as that name broke existing
+dnl configure.ac when using autoheader 2.62.
+ AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
+[/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
+ dnl implies that testing <stdlib.h> is adequate.
+ [AC_LANG_PROGRAM([[
+# define __EXTENSIONS__ 1
+# include <stdlib.h>
+ ]])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_ALL_SOURCE])
+ AC_DEFINE([_GNU_SOURCE])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])# AX_SYS_EXTENSIONS
1
0

20 Jul '12
commit a6051fba5236f7866a3c0967b08e771224948816
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Sat Jun 2 19:18:10 2012 -0700
Add APRAdb registration helper support.
---
Makefile.am | 1 +
configure.ac | 3 +-
src/audit-globals.sh | 11 +-
src/listener.h | 15 ++
src/main.cc | 69 +++++++-
src/network.cc | 16 +--
src/protocol.h | 25 ++-
src/protocol/chop.cc | 12 +-
src/protocol/null.cc | 5 +-
src/steg.h | 6 +-
src/subprocess-unix.cc | 468 ++++++++++++++++++++++++++++++++++++++++++++++++
src/subprocess.h | 68 +++++++
12 files changed, 667 insertions(+), 32 deletions(-)
diff --git a/Makefile.am b/Makefile.am
index 88939fd..a21f053 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -37,6 +37,7 @@ libstegotorus_a_SOURCES = \
src/protocol.cc \
src/rng.cc \
src/socks.cc \
+ src/subprocess-unix.cc \
src/steg.cc \
src/util.cc \
$(PROTOCOLS) $(STEGANOGRAPHERS)
diff --git a/configure.ac b/configure.ac
index 6dc4fe3..4c23af6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -74,7 +74,8 @@ LIBS="$LIBS $ws32_LIBS"
### System features ###
-AC_CHECK_HEADERS([execinfo.h],,,[/**/])
+AC_CHECK_HEADERS([execinfo.h paths.h],,,[/**/])
+AC_CHECK_FUNCS([closefrom execvpe])
### Output ###
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 2a94462..13565aa 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -27,27 +27,28 @@ sed '
# them. The above commands have stripped any leading src/ and/or
# .o or .obj extension.
- # These are genuinely OK.
/^compression ZLIB_CEILING$/d
/^compression ZLIB_UINT_MAX$/d
/^connections circuits$/d
- /^connections connections$/d
/^connections closing_all_connections$/d
+ /^connections connections$/d
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
+ /^crypt init_crypto()::initialized$/d
+ /^crypt log_crypto()::initialized$/d
/^main allow_kq$/d
- /^main the_event_base$/d
/^main handle_signal_cb(int, short, void\*)::got_sigint$/d
+ /^main registration_helper$/d
+ /^main the_event_base$/d
/^network listeners$/d
/^rng rng$/d
+ /^subprocess-unix already_waited$/d
/^util log_dest$/d
/^util log_min_sev$/d
/^util log_timestamps$/d
/^util log_ts_base$/d
/^util the_evdns_base$/d
- /^crypt log_crypto()::initialized$/d
- /^crypt init_crypto()::initialized$/d
')
if [ -n "$symbols" ]; then
diff --git a/src/listener.h b/src/listener.h
index 6a73d1d..6813686 100644
--- a/src/listener.h
+++ b/src/listener.h
@@ -4,8 +4,23 @@
#ifndef LISTENER_H
#define LISTENER_H
+#include <vector>
+
+/**
+ This struct defines the state of a listener on a particular address.
+ */
+struct listener_t
+{
+ config_t *cfg;
+ struct evconnlistener *listener;
+ char *address;
+ size_t index;
+};
+
/* returns 1 on success, 0 on failure */
int listener_open(struct event_base *base, config_t *cfg);
void listener_close_all(void);
+std::vector<listener_t *> const& get_all_listeners();
+
#endif
diff --git a/src/main.cc b/src/main.cc
index 8c1407f..9cc1300 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -10,6 +10,8 @@
#include "crypt.h"
#include "listener.h"
#include "protocol.h"
+#include "steg.h"
+#include "subprocess.h"
#include <vector>
#include <string>
@@ -35,6 +37,7 @@ using std::string;
static struct event_base *the_event_base;
static bool allow_kq = false;
+static string registration_helper;
/**
Puts stegotorus's networking subsystem on "closing time" mode. This
@@ -160,6 +163,59 @@ stdin_detect_eof_cb(evutil_socket_t fd, short, void *arg)
}
/**
+ APRAdb registration hook.
+*/
+static void
+call_registration_helper(string const& helper)
+{
+ vector<string> env = get_environ("ST_");
+ env.push_back("ST_SERVER_KEY=placeholder_server_key");
+
+ vector<listener_t*> const& listeners = get_all_listeners();
+ vector<listener_t*>::const_iterator el;
+ unsigned int n = 0;
+ char buf[512];
+
+ for (el = listeners.begin(); el != listeners.end(); el++, n++) {
+ const steg_config_t *sc = (*el)->cfg->get_steg((*el)->index);
+ if (!sc)
+ continue;
+
+ // The address is in the form x.y.z.w:port or [a:b:c...]:port.
+ // We want IP and port in separate strings. Also, in the latter
+ // case, we want to get rid of the square brackets.
+ string ap((*el)->address);
+ size_t colon = ap.rfind(':');
+ string addr(ap, 0, colon);
+ string port(ap, colon+1);
+
+ if (addr[0] == '[') {
+ addr.erase(addr.size()-1, 1);
+ addr.erase(0,1);
+ }
+
+ if (xsnprintf(buf, sizeof buf, "ST_LISTENER_%u=%s,tcp,%s,%s",
+ n, addr.c_str(), port.c_str(), sc->name()) == -1) {
+ log_warn("listener %u info is too big", n);
+ continue;
+ }
+ env.push_back(buf);
+ }
+
+ vector<string> args;
+ args.push_back(helper);
+ subprocess h = subprocess::call(args, env);
+ if (h.state == CLD_DUMPED) {
+ log_warn("%s: %s (core dumped)", helper.c_str(), strsignal(h.returncode));
+ } else if (h.state == CLD_KILLED) {
+ log_warn("%s: %s", helper.c_str(), strsignal(h.returncode));
+ } else if (h.state == CLD_EXITED && h.returncode != 0) {
+ log_warn("%s: exited unsuccessfully, status %d",
+ helper.c_str(), h.returncode);
+ }
+}
+
+/**
Prints usage instructions then exits.
*/
static void ATTR_NORETURN
@@ -200,6 +256,7 @@ handle_generic_args(const char *const *argv)
bool logsev_set = false;
bool allow_kq_set = false;
bool timestamps_set = false;
+ bool registration_helper_set=false;
int i = 1;
while (argv[i] &&
@@ -250,8 +307,15 @@ handle_generic_args(const char *const *argv)
}
allow_kq = true;
allow_kq_set = true;
+ } else if (!strncmp(argv[i], "--registration-helper=", 22)) {
+ if (registration_helper_set) {
+ fprintf(stderr, "you've already set a registration helper!\n");
+ exit(1);
+ }
+ registration_helper = string(argv[i]+22);
+ registration_helper_set = true;
} else {
- fprintf(stderr, "unrecognizable argument '%s'", argv[i]);
+ fprintf(stderr, "unrecognizable argument '%s'\n", argv[i]);
exit(1);
}
i++;
@@ -409,6 +473,9 @@ main(int, const char *const *argv)
log_abort("failed to open listeners for configuration %lu",
(unsigned long)(i - configs.begin()) + 1);
+ if (!registration_helper.empty())
+ call_registration_helper(registration_helper);
+
/* We are go for launch. As a signal to any monitoring process that may
be running, close stdout now. */
log_info("%s process %lu now initialized", argv[0], (unsigned long)getpid());
diff --git a/src/network.cc b/src/network.cc
index f436ef4..b5f6d4b 100644
--- a/src/network.cc
+++ b/src/network.cc
@@ -20,17 +20,6 @@
using std::vector;
-/**
- This struct defines the state of a listener on a particular address.
- */
-struct listener_t
-{
- config_t *cfg;
- struct evconnlistener *listener;
- char *address;
- size_t index;
-};
-
/** All our listeners. */
static vector<listener_t *> listeners;
@@ -57,6 +46,11 @@ static void downstream_event_cb(struct bufferevent *bev, short what, void *arg);
static void create_outbound_connections(circuit_t *ckt, bool is_socks);
static void create_outbound_connections_socks(circuit_t *ckt);
+vector<listener_t *> const& get_all_listeners()
+{
+ return listeners;
+}
+
/**
This function opens listening sockets configured according to the
provided 'config_t'. Returns 1 on success, 0 on failure.
diff --git a/src/protocol.h b/src/protocol.h
index fbc459e..a2e467d 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -7,6 +7,7 @@
#define PROTOCOL_H
struct proto_module;
+struct steg_config_t;
/** A 'config_t' is a set of addresses to listen on, and what to do
when connections are received. A protocol module must define a
@@ -29,7 +30,7 @@ struct config_t
/** Return the name of the protocol associated with this
configuration. You do not have to define this method in your
subclass, PROTO_DEFINE_MODULE does it for you. */
- virtual const char *name() = 0;
+ virtual const char *name() const = 0;
/** Initialize yourself from a set of command line options. This is
separate from the subclass constructor so that it can fail:
@@ -42,7 +43,7 @@ struct config_t
users of this function should call it repeatedly with successive
values of N, starting from zero, until it returns NULL, and
create listeners for every address returned. */
- virtual evutil_addrinfo *get_listen_addrs(size_t n) = 0;
+ virtual evutil_addrinfo *get_listen_addrs(size_t n) const = 0;
/** Return a set of addresses to attempt an outbound connection to,
in the form of an 'evutil_addrinfo' linked list. As with
@@ -50,7 +51,12 @@ struct config_t
should in general attempt simultaneous connection to at least
one address from every list. The maximum N is indicated in the
same way as for get_listen_addrs. */
- virtual evutil_addrinfo *get_target_addrs(size_t n) = 0;
+ virtual evutil_addrinfo *get_target_addrs(size_t n) const = 0;
+
+ /** Return the steganography module associated with either listener
+ or target address set N. If called on a protocol that doesn't
+ use steganography, will return NULL. */
+ virtual const steg_config_t *get_steg(size_t n) const = 0;
/** Return an extended 'circuit_t' object for a new socket using
this configuration. The 'index' argument is equal to the 'N'
@@ -87,7 +93,7 @@ extern const proto_module *const supported_protos[];
#define PROTO_DEFINE_MODULE(mod) \
/* canned methods */ \
- const char *mod##_config_t::name() \
+ const char *mod##_config_t::name() const \
{ return #mod; } \
\
static config_t * \
@@ -106,14 +112,19 @@ extern const proto_module *const supported_protos[];
#define CONFIG_DECLARE_METHODS(mod) \
mod##_config_t(); \
virtual ~mod##_config_t(); \
- virtual const char *name(); \
+ virtual const char *name() const; \
virtual bool init(int n_opts, const char *const *opts); \
- virtual evutil_addrinfo *get_listen_addrs(size_t n); \
- virtual evutil_addrinfo *get_target_addrs(size_t n); \
+ virtual evutil_addrinfo *get_listen_addrs(size_t n) const; \
+ virtual evutil_addrinfo *get_target_addrs(size_t n) const; \
+ virtual const steg_config_t *get_steg(size_t n) const; \
virtual circuit_t *circuit_create(size_t index); \
virtual conn_t *conn_create(size_t index) \
/* deliberate absence of semicolon */
+#define CONFIG_STEG_STUBS(mod) \
+ const steg_config_t *mod##_config_t::get_steg(size_t) const \
+ { return 0; }
+
#define CONN_DECLARE_METHODS(mod) \
mod##_conn_t(); \
virtual ~mod##_conn_t(); \
diff --git a/src/protocol/chop.cc b/src/protocol/chop.cc
index 5451925..f547303 100644
--- a/src/protocol/chop.cc
+++ b/src/protocol/chop.cc
@@ -475,7 +475,7 @@ chop_config_t::init(int n_options, const char *const *options)
}
struct evutil_addrinfo *
-chop_config_t::get_listen_addrs(size_t n)
+chop_config_t::get_listen_addrs(size_t n) const
{
if (mode == LSN_SIMPLE_SERVER) {
if (n < down_addresses.size())
@@ -488,7 +488,7 @@ chop_config_t::get_listen_addrs(size_t n)
}
struct evutil_addrinfo *
-chop_config_t::get_target_addrs(size_t n)
+chop_config_t::get_target_addrs(size_t n) const
{
if (mode == LSN_SIMPLE_SERVER) {
if (n == 0)
@@ -500,6 +500,14 @@ chop_config_t::get_target_addrs(size_t n)
return NULL;
}
+const steg_config_t *
+chop_config_t::get_steg(size_t n) const
+{
+ if (n < steg_targets.size())
+ return steg_targets[n];
+ return NULL;
+}
+
// Circuit methods
const char passphrase[] =
diff --git a/src/protocol/null.cc b/src/protocol/null.cc
index 90abec2..d8fe98b 100644
--- a/src/protocol/null.cc
+++ b/src/protocol/null.cc
@@ -102,7 +102,7 @@ null_config_t::init(int n_options, const char *const *options)
/** Retrieve the 'n'th set of listen addresses for this configuration. */
struct evutil_addrinfo *
-null_config_t::get_listen_addrs(size_t n)
+null_config_t::get_listen_addrs(size_t n) const
{
if (n > 0)
return 0;
@@ -111,7 +111,7 @@ null_config_t::get_listen_addrs(size_t n)
/* Retrieve the target address for this configuration. */
struct evutil_addrinfo *
-null_config_t::get_target_addrs(size_t n)
+null_config_t::get_target_addrs(size_t n) const
{
if (n > 0)
return 0;
@@ -287,4 +287,5 @@ null_conn_t::recv_eof()
return 0;
}
+CONFIG_STEG_STUBS(null);
CONN_STEG_STUBS(null);
diff --git a/src/steg.h b/src/steg.h
index fe8ef5e..f042864 100644
--- a/src/steg.h
+++ b/src/steg.h
@@ -26,7 +26,7 @@ struct steg_config_t
/** Report the name of this steg module. You do not have to define
this method in your subclass, STEG_DEFINE_MODULE does it for you. */
- virtual const char *name() = 0;
+ virtual const char *name() const = 0;
/** Create an extended 'steg_t' object (see below) from this
configuration, associated with connection CONN. */
@@ -110,7 +110,7 @@ steg_config_t *steg_new(const char *name, config_t *cfg);
{ return new mod##_steg_config_t(cfg); } \
\
/* canned methods */ \
- const char *mod##_steg_config_t::name() \
+ const char *mod##_steg_config_t::name() const \
{ return #mod; } \
\
/* module object */ \
@@ -121,7 +121,7 @@ steg_config_t *steg_new(const char *name, config_t *cfg);
#define STEG_CONFIG_DECLARE_METHODS(mod) \
mod##_steg_config_t(config_t *); \
virtual ~mod##_steg_config_t(); \
- virtual const char *name(); \
+ virtual const char *name() const; \
virtual steg_t *steg_create(conn_t *) \
/* deliberate absence of semicolon */
diff --git a/src/subprocess-unix.cc b/src/subprocess-unix.cc
new file mode 100644
index 0000000..7e4b8a2
--- /dev/null
+++ b/src/subprocess-unix.cc
@@ -0,0 +1,468 @@
+/* Copyright 2012 SRI International
+ * Portions copyright 2003-2011 Roger Dingledine, Nick Mathewson,
+ * and/or The Tor Project, Inc.
+ * Portions copyright 1991-2012 The Regents of the University of California
+ * and/or various FreeBSD contributors.
+ * See LICENSE for other credits and copying information.
+ */
+
+// N.B. This file will have to be rewritten more-or-less from scratch
+// for the Windows port. It should be acceptably portable to all Unix
+// implementations still in wide use.
+
+#include "util.h"
+#include "subprocess.h"
+
+#include <map>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef HAVE_PATHS_H
+#include <paths.h>
+#endif
+#ifndef _PATH_DEFPATH
+#define _PATH_DEFPATH "/usr/bin:/bin"
+#endif
+
+#ifndef PATH_MAX
+# ifdef MAXPATHLEN
+# define PATH_MAX MAXPATHLEN
+# else
+# define PATH_MAX 4096
+# endif
+#endif
+
+#ifndef OPEN_MAX
+# define OPEN_MAX 256
+#endif
+
+extern char **environ;
+
+using std::map;
+using std::vector;
+using std::string;
+
+
+// Space for hex values of child state, a slash, saved_errno (with
+// leading minus) and newline (no null)
+#define HEX_ERRNO_SIZE (sizeof(int)*2 + 4)
+
+// State codes for the child side of the fork.
+#define CHILD_STATE_REDIRECT_STDIN 1
+#define CHILD_STATE_REDIRECT_STDOUT 2
+#define CHILD_STATE_REDIRECT_STDERR 3
+#define CHILD_STATE_CLOSEFROM 4
+#define CHILD_STATE_EXEC 5
+
+// Some C libraries get very unhappy with you if you ignore the result
+// of a write call, but where it's used in this file, there is nothing
+// whatsoever we can do if it fails.
+#define IGNORE_FAILURE(expr) do { if (expr) {} } while (0)
+
+// We have not prevented copying of |subprocess| objects, so it is
+// possible that |wait| will be called more than once for the same
+// PID, with no state in the object to tell us so. To prevent
+// problems, maintain a table of processes that we have waited for.
+// We make no attempt to prune this table; its memory requirements
+// should be trivial for the expected uses of this API.
+static map<pid_t, int> already_waited;
+
+// Internal utilities and replacements for system library routines
+// that may or may not exist.
+
+#ifndef HAVE_CLOSEFROM
+static void
+closefrom(int lowfd)
+{
+#ifdef F_CLOSEM
+ // Try F_CLOSEM if it's defined. But it might not work.
+ if (fcntl(lowfd, F_CLOSEM, 0) == 0)
+ return;
+#endif
+
+ // If /proc/self/fd is available, use it.
+ // N.B. Theoretically you are not allowed to use opendir() after fork()
+ // as it's not async-signal-safe. This is overwhelmingly unlikely to
+ // cause problems in practice.
+ DIR *dirp;
+ if ((dirp = opendir("/proc/self/fd")) != 0) {
+ struct dirent *dent;
+ char *endp;
+ while ((dent = readdir(dirp)) != NULL) {
+ unsigned long fd = strtoul(dent->d_name, &endp, 10);
+ if (dent->d_name != endp && *endp == '\0' &&
+ fd < (unsigned long)INT_MAX &&
+ fd >= (unsigned long)lowfd &&
+ fd != (unsigned long)dirfd(dirp))
+ close((int)fd);
+ }
+ closedir(dirp);
+ return;
+ }
+
+ // As a last resort, blindly close all possible fd numbers
+ // between lowfd and _SC_OPEN_MAX.
+ unsigned long maxfd = sysconf(_SC_OPEN_MAX);
+ if (maxfd == (unsigned long)(-1L))
+ maxfd = OPEN_MAX;
+ for (unsigned long fd = lowfd; fd < maxfd; fd++)
+ close((int)fd);
+}
+#endif
+
+#ifndef HAVE_EXECVPE
+// Implementation courtesy FreeBSD 9.0 src/lib/libc/gen/exec.c
+// some adjustments made with reference to the glibc implementation
+static int
+execvpe(const char *name, char * const argv[], char * const envp[])
+{
+ const char *path;
+ const char *p, *q;
+ size_t lp, ln;
+ bool eacces = false;
+ char buf[PATH_MAX];
+
+ // If it's an empty path name, fail immediately.
+ if (*name == '\0') {
+ errno = ENOENT;
+ return -1;
+ }
+
+ // If it's an absolute or relative pathname, do not search $PATH.
+ if (strchr(name, '/')) {
+ execve(name, argv, envp);
+ return -1;
+ }
+ ln = strlen(name);
+
+ // Get the path to search. Intentionally uses the parent
+ // environment, not 'envp'.
+ if (!(path = getenv("PATH")))
+ path = _PATH_DEFPATH;
+
+ q = path;
+ do {
+ p = q;
+ while (*q != '\0' && *q != ':')
+ q++;
+
+ // Double, leading and trailing colons mean the current directory.
+ if (q == p) {
+ p = ".";
+ lp = 1;
+ } else
+ lp = q - p;
+ q++;
+
+ // If the path is too long, complain and skip it. This is a
+ // possible security issue; given a way to make the path too long
+ // the user may execute the wrong program.
+ if (lp + ln + 2 > sizeof(buf)) {
+ IGNORE_FAILURE(write(2, "execvpe: ", 8));
+ IGNORE_FAILURE(write(2, p, lp));
+ IGNORE_FAILURE(write(2, ": path too long\n", 16));
+ continue;
+ }
+
+ memcpy(buf, p, lp);
+ buf[lp] = '/';
+ memcpy(buf + lp + 1, name, ln);
+ buf[lp + ln + 1] = '\0';
+
+ execve(buf, argv, envp);
+ switch (errno) {
+ // These errors all indicate that we should try the next directory.
+ case EACCES:
+ // Remember that at least one failure was due to a permission check;
+ // this will be preferentially reported, unless we hit something even
+ // more serious.
+ eacces = true;
+ case ELOOP:
+ case ENAMETOOLONG:
+ case ENOENT:
+ case ENOTDIR:
+ case ESTALE:
+ case ETIMEDOUT:
+ continue;
+
+ default:
+ // On any other error, give up.
+ // Shell fallback for ENOEXEC deliberately removed, as it is a
+ // historical vestige and involves allocating memory.
+ return -1;
+ }
+ } while (*q);
+
+ if (eacces)
+ errno = EACCES;
+ return -1;
+}
+#endif
+
+/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
+ * <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
+ * safe.
+ *
+ * <b>hex_errno</b> must have at least HEX_ERRNO_SIZE bytes available.
+ *
+ * The format of <b>hex_errno</b> is: "CHILD_STATE/ERRNO\n", left-padded
+ * with spaces. Note that there is no trailing \0. CHILD_STATE indicates where
+ * in the processs of starting the child process did the failure occur (see
+ * CHILD_STATE_* macros for definition), and SAVED_ERRNO is the value of
+ * errno when the failure occurred.
+ */
+static void
+format_helper_exit_status(unsigned char child_state, int saved_errno,
+ char *hex_errno)
+{
+ unsigned int unsigned_errno;
+ char *cur;
+ size_t i;
+
+ /* Fill hex_errno with spaces, and a trailing newline (memset may
+ not be signal handler safe, so we can't use it) */
+ for (i = 0; i < (HEX_ERRNO_SIZE - 1); i++)
+ hex_errno[i] = ' ';
+ hex_errno[HEX_ERRNO_SIZE - 1] = '\n';
+
+ /* Convert errno to be unsigned for hex conversion */
+ if (saved_errno < 0) {
+ unsigned_errno = (unsigned int) -saved_errno;
+ } else {
+ unsigned_errno = (unsigned int) saved_errno;
+ }
+
+ /* Convert errno to hex (start before \n) */
+ cur = hex_errno + HEX_ERRNO_SIZE - 2;
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ do {
+ *cur-- = "0123456789ABCDEF"[unsigned_errno % 16];
+ unsigned_errno /= 16;
+ } while (unsigned_errno != 0 && cur >= hex_errno);
+
+ /* Prepend the minus sign if errno was negative */
+ if (saved_errno < 0 && cur >= hex_errno)
+ *cur-- = '-';
+
+ /* Leave a gap */
+ if (cur >= hex_errno)
+ *cur-- = '/';
+
+ /* Check for overflow on first iteration of the loop */
+ if (cur < hex_errno)
+ return;
+
+ /* Convert child_state to hex */
+ do {
+ *cur-- = "0123456789ABCDEF"[child_state % 16];
+ child_state /= 16;
+ } while (child_state != 0 && cur >= hex_errno);
+}
+
+/** Start a program in the background. If <b>filename</b> contains a '/',
+ * then it will be treated as an absolute or relative path. Otherwise the
+ * system path will be searched for <b>filename</b>. The strings in
+ * <b>argv</b> will be passed as the command line arguments of the child
+ * program (following convention, argv[0] should normally be the filename of
+ * the executable), and the strings in <b>envp</b> will be passed as its
+ * environment variables.
+ *
+ * The child's standard input and output will both be /dev/null;
+ * the child's standard error will be whatever it is in the parent
+ * (unless it is closed in the parent, in which case it will also be
+ * /dev/null)
+ *
+ * All file descriptors numbered higher than 2 will be closed.
+ *
+ * On success, returns the PID of the child; on failure, returns -1.
+ */
+static pid_t
+do_fork_exec(const char *const filename,
+ const char **argv,
+ const char **envp)
+{
+ pid_t pid = fork();
+
+ if (pid == -1) {
+ log_warn("Failed to fork child process: %s", strerror(errno));
+ return -1;
+ }
+
+ if (pid != 0) {
+ // In parent.
+ // If we spawn a child, wait for it, the PID counter wraps
+ // completely around, and then we spawn another child which
+ // happens to get exactly the same PID as the first one, we had
+ // better remove the old record from the already_waited table or
+ // we won't ever actually wait for the new child. The odds of
+ // this are small, but not ridiculously small.
+ already_waited.erase(pid);
+ return pid;
+ }
+
+ // In child
+ char hex_errno[HEX_ERRNO_SIZE];
+ unsigned int child_state = CHILD_STATE_REDIRECT_STDIN;
+
+ close(0);
+ if (open("/dev/null", O_RDONLY) != 0)
+ goto error;
+
+ child_state = CHILD_STATE_REDIRECT_STDOUT;
+
+ close(1);
+ if (open("/dev/null", O_WRONLY) != 1)
+ goto error;
+
+ child_state = CHILD_STATE_REDIRECT_STDERR;
+ if (!isatty(2) && errno == EBADF) {
+ if (open("/dev/null", O_WRONLY) != 2)
+ goto error;
+ }
+
+ child_state = CHILD_STATE_CLOSEFROM;
+ closefrom(3);
+
+ child_state = CHILD_STATE_EXEC;
+
+ // We need the casts because execvpe doesn't declare argv or envp
+ // as const, even though it does not modify them.
+ execvpe(filename, (char *const *) argv, (char *const *)envp);
+
+ error:
+ format_helper_exit_status(child_state, errno, hex_errno);
+
+#define error_message "ERR: Failed to spawn child process: code "
+
+ IGNORE_FAILURE(write(2, error_message, sizeof error_message - 1));
+ IGNORE_FAILURE(write(2, hex_errno, sizeof hex_errno));
+
+#undef error_message
+
+ _exit(255);
+}
+
+// Wrapper: marshal the C++-y vector and map into the form the kernel
+// expects.
+static pid_t
+do_fork_exec(vector<string> const& args,
+ vector<string> const& env)
+{
+ char const* argv[args.size() + 1];
+ char const* envp[env.size() + 1];
+
+ for (size_t i = 0; i < args.size(); i++)
+ argv[i] = args[i].c_str();
+ argv[args.size()] = 0;
+
+ for (size_t i = 0; i < env.size(); i++)
+ envp[i] = env[i].c_str();
+ envp[env.size()] = 0;
+
+ return do_fork_exec(argv[0], argv, envp);
+}
+
+static void
+decode_status(int status, int& state, int& rc)
+{
+ if (WIFEXITED(status)) {
+ rc = WEXITSTATUS(status);
+ state = CLD_EXITED;
+ } else if (WIFSIGNALED(status)) {
+ rc = WTERMSIG(status);
+#ifdef WCOREDUMP
+ if (WCOREDUMP(status))
+ state = CLD_DUMPED;
+ else
+#endif
+ state = CLD_KILLED;
+ } else {
+ // we do not use WUNTRACED, WCONTINUED, or ptrace, so the other
+ // WIF* possibilities should never happen
+ log_abort("impossible wait status %04x", (unsigned int)status);
+ }
+}
+
+static bool
+wait_common(pid_t pid, int& state, int& rc, bool wnohang)
+{
+ if (pid == -1) {
+ // Map failure to fork into the same exit state that we get if
+ // there's a failure in between fork and exec.
+ state = CLD_EXITED;
+ rc = 255;
+ return true;
+ }
+
+ map<pid_t, int>::iterator p = already_waited.find(pid);
+ if (p != already_waited.end()) {
+ decode_status(p->second, state, rc);
+ return true;
+ }
+
+ int status;
+ pid_t rv = waitpid(pid, &status, wnohang ? WNOHANG : 0);
+ if (rv == pid) {
+ decode_status(status, state, rc);
+ already_waited.insert(std::make_pair(pid, status));
+ return true;
+ } else if (rv == 0 && wnohang) {
+ return false;
+ } else {
+ log_warn("waitpid(%d) failed: %s", pid, strerror(errno));
+ return false;
+ }
+}
+
+// subprocess methods
+
+subprocess::subprocess(vector<string> const& args,
+ vector<string> const& env)
+ : pid(do_fork_exec(args, env)),
+ state(0),
+ returncode(-1)
+{
+}
+
+subprocess
+subprocess::call(vector<string> const& args, vector<string> const& env)
+{
+ subprocess proc(args, env);
+ proc.wait();
+ return proc;
+}
+
+bool
+subprocess::poll()
+{
+ return wait_common(pid, state, returncode, true);
+}
+
+void
+subprocess::wait()
+{
+ wait_common(pid, state, returncode, false);
+}
+
+// public utilities
+
+vector<string>
+get_environ(const char *exclude)
+{
+ vector<string> result;
+ size_t exlen = exclude ? strlen(exclude) : 0;
+
+ for (char **p = environ; *p; p++)
+ if (!exclude || strncmp(exclude, *p, exlen))
+ result.push_back(*p);
+
+ return result;
+}
diff --git a/src/subprocess.h b/src/subprocess.h
new file mode 100644
index 0000000..95fe848
--- /dev/null
+++ b/src/subprocess.h
@@ -0,0 +1,68 @@
+/* Copyright 2012 SRI International
+ * See LICENSE for other credits and copying information
+ */
+
+#ifndef SUBPROCESS_H
+#define SUBPROCESS_H
+
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+// This API is inspired by the Python subprocess module. While it
+// could be extended to do everything that that does, at present it
+// does much less. If you add features, please consider matching
+// Python's presentation of same.
+
+#ifndef CLD_EXITED
+#define CLD_EXITED 1
+#endif
+#ifndef CLD_KILLED
+#define CLD_KILLED 2
+#endif
+#ifndef CLD_DUMPED
+#define CLD_DUMPED 3
+#endif
+
+struct subprocess
+{
+ // Start a new subprocess with argument vector |args| and environment
+ // vector |env|. stdin and stdout are /dev/null. stderr is inherited.
+ // All file descriptors numbered 3 and higher are closed.
+ // The current working directory is inherited.
+ subprocess(std::vector<std::string> const& args,
+ std::vector<std::string> const& env);
+
+ // Convenience: spawn a subprocess and wait for it to terminate.
+ static subprocess call(std::vector<std::string> const& args,
+ std::vector<std::string> const& env);
+
+ // Check whether the child process has terminated. Returns true if it
+ // has, false otherwise; sets 'state' and 'returncode'.
+ bool poll();
+
+ // Wait for the child process to terminate.
+ void wait();
+
+ // Process ID of the child. -1 on failure to spawn, in which case
+ // an error message has already been logged.
+ const pid_t pid;
+
+ // Child state, either 0 (running) or one of the <signal.h> constants
+ // CLD_EXITED, CLD_KILLED, or CLD_DUMPED.
+ int state;
+
+ // Exit status (if state == CLD_EXITED) or signal that terminated the
+ // process (if state == CLD_KILLED or CLD_DUMPED); -1 otherwise.
+ int returncode;
+};
+
+// Convert the global environment vector to a C++ vector.
+// If 'exclude' is not NULL, then any environment variable whose name
+// begins with those characters will be excluded from the result.
+extern std::vector<std::string> get_environ(const char *exclude = 0);
+
+#endif
1
0

[stegotorus/master] Prepare for having more than one file that touches OpenSSL.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 8a0c099d09284c6717b599c6d70c4cc1913ecc55
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 13:49:59 2012 -0700
Prepare for having more than one file that touches OpenSSL.
* Expose init_crypto, log_crypto_abort, and log_crypto_warn.
* Use an explicit teardown function for OpenSSL state instead of
relying on atexit().
Portability/reliability fixes en passant.
* Clarify situation with malloc/realloc in configure.ac.
* Actually check whether we need -lm for floor().
* Use CRYPTO_set_mem_functions to send OpenSSL-internal
memory allocations through xmalloc/xrealloc.
---
configure.ac | 11 +++++---
src/audit-globals.sh | 4 +-
src/crypt.cc | 72 +++++++++++++++++++++++++++++--------------------
src/crypt.h | 27 ++++++++++++++++++
src/main.cc | 3 ++
src/test/unittest.cc | 4 +++
6 files changed, 86 insertions(+), 35 deletions(-)
diff --git a/configure.ac b/configure.ac
index ab56311..889cfae 100644
--- a/configure.ac
+++ b/configure.ac
@@ -16,14 +16,12 @@ dnl with a rationale for each:
dnl
dnl Defined by C89, therefore unnecessary to check for nowadays:
dnl
-dnl AC_CHECK_FUNCS([atexit floor memset strcasecmp strchr strerror
-dnl strrchr strstr strtoul])
+dnl AC_CHECK_FUNCS([memset strcasecmp strchr strerror strrchr strstr strtoul])
dnl AC_CHECK_HEADERS([limits.h stddef.h stdlib.h string.h])
dnl AC_CHECK_TYPES([ptrdiff_t])
dnl AC_TYPE_SIZE_T
dnl
-dnl We don't make use of the unspecified-behavior corner cases that
-dnl these pin down:
+dnl Dealt with by our 'xmalloc' and 'xrealloc' wrappers:
dnl
dnl AC_FUNC_MALLOC
dnl AC_FUNC_REALLOC
@@ -136,6 +134,11 @@ AC_SUBST(lib_CPPFLAGS)
AX_LIB_WINSOCK2
LIBS="$LIBS $ws32_LIBS"
+# We might need to explicitly link -lm for floor().
+AC_SEARCH_LIBS([floor], [m], [], [
+ AC_MSG_ERROR([unable to find 'floor'])
+])
+
### System features ###
AC_CHECK_HEADERS([execinfo.h paths.h],,,[/**/])
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 13565aa..025549f 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -35,8 +35,8 @@ sed '
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
- /^crypt init_crypto()::initialized$/d
- /^crypt log_crypto()::initialized$/d
+ /^crypt crypto_initialized$/d
+ /^crypt crypto_errs_initialized$/d
/^main allow_kq$/d
/^main handle_signal_cb(int, short, void\*)::got_sigint$/d
/^main registration_helper$/d
diff --git a/src/crypt.cc b/src/crypt.cc
index 053f7e6..d4af5e0 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -11,30 +11,46 @@
#include <openssl/evp.h>
#include <openssl/hmac.h>
-static void
+static bool crypto_initialized = false;
+static bool crypto_errs_initialized = false;
+
+#define REQUIRE_INIT_CRYPTO() \
+ log_assert(crypto_initialized)
+
+void
init_crypto()
{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
- ENGINE_load_builtin_engines();
- ENGINE_register_all_complete();
- atexit(ENGINE_cleanup);
-
- // we don't need to call OpenSSL_add_all_algorithms or EVP_cleanup,
- // since we never look up ciphers by textual name.
- }
+ log_assert(!crypto_initialized);
+
+ crypto_initialized = true;
+ CRYPTO_set_mem_functions(xmalloc, xrealloc, free);
+ ENGINE_load_builtin_engines();
+ ENGINE_register_all_complete();
+
+ // we don't need to call OpenSSL_add_all_algorithms, since we never
+ // look up ciphers by textual name.
+}
+
+void
+free_crypto()
+{
+ // we don't need to call EVP_cleanup, since we never called
+ // OpenSSL_add_all_algorithms.
+
+ if (crypto_initialized)
+ ENGINE_cleanup();
+ if (crypto_errs_initialized)
+ ERR_free_strings();
}
static void
log_crypto()
{
- static bool initialized = false;
- if (!initialized) {
- initialized = true;
+ if (!crypto_errs_initialized) {
+ crypto_errs_initialized = true;
ERR_load_crypto_strings();
- atexit(ERR_free_strings);
}
+
unsigned long err;
while ((err = ERR_get_error()) != 0)
log_warn("%s: %s: %s",
@@ -43,14 +59,14 @@ log_crypto()
ERR_reason_error_string(err));
}
-static void ATTR_NORETURN
+void ATTR_NORETURN
log_crypto_abort(const char *msg)
{
log_crypto();
log_abort("libcrypto error in %s", msg);
}
-static int
+int
log_crypto_warn(const char *msg)
{
log_crypto();
@@ -145,7 +161,7 @@ namespace {
ecb_encryptor *
ecb_encryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
ecb_encryptor_impl *enc = new ecb_encryptor_impl;
if (!EVP_EncryptInit_ex(&enc->ctx, aes_ecb_by_size(keylen), 0, key, 0))
@@ -159,7 +175,7 @@ ecb_encryptor::create(const uint8_t *key, size_t keylen)
ecb_encryptor *
ecb_encryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -177,7 +193,7 @@ ecb_encryptor::create(key_generator *gen, size_t keylen)
ecb_decryptor *
ecb_decryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
ecb_decryptor_impl *dec = new ecb_decryptor_impl;
if (!EVP_DecryptInit_ex(&dec->ctx, aes_ecb_by_size(keylen), 0, key, 0))
@@ -191,7 +207,7 @@ ecb_decryptor::create(const uint8_t *key, size_t keylen)
ecb_decryptor *
ecb_decryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -272,7 +288,7 @@ namespace {
gcm_encryptor *
gcm_encryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
gcm_encryptor_impl *enc = new gcm_encryptor_impl;
if (!EVP_EncryptInit_ex(&enc->ctx, aes_gcm_by_size(keylen), 0, key, 0))
@@ -284,7 +300,7 @@ gcm_encryptor::create(const uint8_t *key, size_t keylen)
gcm_encryptor *
gcm_encryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -300,7 +316,7 @@ gcm_encryptor::create(key_generator *gen, size_t keylen)
gcm_decryptor *
gcm_decryptor::create(const uint8_t *key, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
gcm_decryptor_impl *dec = new gcm_decryptor_impl;
if (!EVP_DecryptInit_ex(&dec->ctx, aes_gcm_by_size(keylen), 0, key, 0))
@@ -312,7 +328,7 @@ gcm_decryptor::create(const uint8_t *key, size_t keylen)
gcm_decryptor *
gcm_decryptor::create(key_generator *gen, size_t keylen)
{
- init_crypto();
+ REQUIRE_INIT_CRYPTO();
MemBlock key(keylen);
size_t got = gen->generate(key, keylen);
@@ -430,6 +446,7 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
const uint8_t *ctxt, size_t clen)
{
log_assert(klen <= INT_MAX && slen < INT_MAX && clen < INT_MAX);
+ REQUIRE_INIT_CRYPTO();
MemBlock prk(SHA256_LEN);
@@ -438,8 +455,6 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
slen = SHA256_LEN;
}
- init_crypto();
-
if (HMAC(EVP_sha256(), salt, slen, key, klen, prk, 0) == 0)
log_crypto_abort("key_generator::from_random_secret");
@@ -460,6 +475,7 @@ key_generator::from_passphrase(const uint8_t *phra, size_t plen,
// salt, then put the result through HKDF-Extract with the salt.
log_assert(plen <= INT_MAX && slen < INT_MAX);
+ REQUIRE_INIT_CRYPTO();
MemBlock prk(SHA256_LEN);
@@ -468,8 +484,6 @@ key_generator::from_passphrase(const uint8_t *phra, size_t plen,
slen = SHA256_LEN;
}
- init_crypto();
-
if (!PKCS5_PBKDF2_HMAC((const char *)phra, plen, salt, slen,
10000, EVP_sha256(), SHA256_LEN, prk))
log_crypto_abort("key_generator::from_passphrase");
diff --git a/src/crypt.h b/src/crypt.h
index d7e5fbf..4da3309 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -9,6 +9,33 @@ const size_t AES_BLOCK_LEN = 16;
const size_t GCM_TAG_LEN = 16;
const size_t SHA256_LEN = 32;
+/**
+ * Initialize cryptography library. Must be called before anything that
+ * uses any of the APIs below.
+ */
+void init_crypto();
+
+/**
+ * Tear down cryptography library.
+ */
+void free_crypto();
+
+/**
+ * Report a cryptography failure.
+ * @msg should describe the operation that failed.
+ * Always returns -1; this allows you to write
+ * if (some operation failed)
+ * return log_crypto_warn("some operation");
+ */
+int log_crypto_warn(const char *msg);
+
+/**
+ * Report a cryptography failure which is a fatal error.
+ * @msg should describe the operation that failed.
+ * Does not return.
+ */
+void ATTR_NORETURN log_crypto_abort(const char *msg);
+
struct key_generator;
struct ecb_encryptor
diff --git a/src/main.cc b/src/main.cc
index 9cc1300..dd69e68 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -381,6 +381,8 @@ main(int, const char *const *argv)
/* Configurations have been established; proceed with initialization. */
+ init_crypto();
+
/* Ugly method to fix a Windows problem:
http://archives.seul.org/libevent/users/Oct-2010/msg00049.html */
#ifdef _WIN32
@@ -499,6 +501,7 @@ main(int, const char *const *argv)
free(stdin_eof);
event_base_free(the_event_base);
event_config_free(evcfg);
+ free_crypto();
log_close();
return 0;
diff --git a/src/test/unittest.cc b/src/test/unittest.cc
index cba4906..958c82c 100644
--- a/src/test/unittest.cc
+++ b/src/test/unittest.cc
@@ -108,6 +108,8 @@ main(int argc, const char **argv)
log_set_method(LOG_METHOD_NULL, 0);
}
+ init_crypto();
+
/* Ugly method to fix a Windows problem:
http://archives.seul.org/libevent/users/Oct-2010/msg00049.html */
#ifdef _WIN32
@@ -118,7 +120,9 @@ main(int argc, const char **argv)
#endif
rv = tinytest_main(argc, argv, unittest_groups);
+
conn_start_shutdown(1);
+ free_crypto();
return rv;
}
1
0
commit f0eff04bd637c4536f73fa7bc71d233c5e644036
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 10:14:18 2012 -0700
Top level directory tidying.
---
.gitignore | 7 +-
LICENSE | 14 +++-
Makefile.am | 2 +-
README.Linda | 117 ----------------------------
config-aux/cxx_delete_method.m4 | 78 +++++++++++++++++++
config-aux/cxx_static_assert.m4 | 57 ++++++++++++++
config-aux/cxxflags_stdcxx_11.m4 | 102 ++++++++++++++++++++++++
config-aux/maintainer.m4 | 39 +++++++++
config-aux/pkg.m4 | 159 ++++++++++++++++++++++++++++++++++++++
config-aux/ranlib.m4 | 69 ++++++++++++++++
config-aux/system_extensions.m4 | 81 +++++++++++++++++++
config-aux/winsock.m4 | 56 +++++++++++++
configure.ac | 1 +
doc/README.Linda | 117 ++++++++++++++++++++++++++++
m4/cxx_delete_method.m4 | 78 -------------------
m4/cxx_static_assert.m4 | 57 --------------
m4/cxxflags_stdcxx_11.m4 | 102 ------------------------
m4/maintainer.m4 | 39 ---------
m4/pkg.m4 | 159 --------------------------------------
m4/ranlib.m4 | 69 ----------------
m4/system_extensions.m4 | 81 -------------------
m4/winsock.m4 | 56 -------------
22 files changed, 773 insertions(+), 767 deletions(-)
diff --git a/.gitignore b/.gitignore
index 8de7c1e..aa3eb46 100644
--- a/.gitignore
+++ b/.gitignore
@@ -16,7 +16,6 @@
/aclocal.m4
/autom4te.cache
-/compile
/config.guess
/config.h
/config.h.in
@@ -24,12 +23,12 @@
/config.status
/config.sub
/configure
-/depcomp
-/install-sh
/Makefile
/Makefile.in
-/missing
/stamp-*
+/config-aux/depcomp
+/config-aux/install-sh
+/config-aux/missing
/protolist.c
/steglist.c
diff --git a/LICENSE b/LICENSE
index 3bcae2b..7aea274 100644
--- a/LICENSE
+++ b/LICENSE
@@ -34,7 +34,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
=====
-The files in m4/ and scripts/ each have their own individual copyright
-and licensing, which may be more or less permissive than the above
-license. However, those licenses DO NOT extend to the collective
-work, the generated configure script, or to StegoTorus itself.
+Some files in src/ contain material which is copyright other people
+or organizations, and which may be licensed more permissively than the
+above. Comments at the top of each file document its precise provenance
+and licensing.
+
+All the files in config-aux/ and scripts/ have their own copyright and
+licensing, indicated in comments at the top of the file; these licenses
+may be more or *less* permissive than the above. Those licenses DO NOT
+extend to the collective work, the generated configure script, or to
+StegoTorus itself.
diff --git a/Makefile.am b/Makefile.am
index a21f053..64d1d33 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -2,7 +2,7 @@
# Copyright 2011, 2012 SRI International
# See LICENSE for other credits and copying information
-ACLOCAL_AMFLAGS = -I m4 --install
+ACLOCAL_AMFLAGS = -I config-aux --install
AM_CXXFLAGS = -Werror -Wall -Wextra -Wformat=2
AM_CPPFLAGS = -I. -I$(srcdir)/src -D_FORTIFY_SOURCE=2 $(lib_CPPFLAGS)
diff --git a/README.Linda b/README.Linda
deleted file mode 100644
index 3cb4d2e..0000000
--- a/README.Linda
+++ /dev/null
@@ -1,117 +0,0 @@
-compiling stegotorus on Mac OS X 10.6
-=====================================
-
-0) prelims
-
-Install Mac Ports from http://www.macports.org (here v2.0.3).
-$> sudo port selfupdate [for good measure]
-
- a) autoconf 2.68
-
-$> sudo port install autoconf
-$> autoconf --version
-autoconf (GNU Autoconf) 2.68
-
- b) automake 1.11
-
-$> sudo port install automake
-$> automake --version
-automake (GNU automake) 1.11.1
-
- c) pkgconfig
-
-$> sudo port install pkgconfig
-
- d) openssl >= 1.0.1, libevent-2
-
-$> sudo port install openssl
-$> sudo port install libevent
-
- e) tor
-
-$> sudo port install tor
-$> tor --version
-[...]
-Tor version 0.2.2.34 (git-c4eae752f0d157ce).
-
-
-1) StegoTorus
-
-$> cd ~/src/DEFIANCE/stegotorus/sri
-$> autoreconf -i
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
-
-No package 'libcrypto++' found
-[...]
-$> sudo cp Desktop/libcrypto++.pc /usr/lib/pkgconfig/
-$> ./configure --disable-integration-tests --enable-silent-rules
-$> make
-
-
-compiling stegotorus under Ubuntu 11.10
-=======================================
-
-$> sudo apt-get install pkg-config libevent-2.0-5 libevent-dev
-
-Tor:
-----
-
-$> sudo cat >> /etc/apt/sources.list <<EOF
-> deb http://deb.torproject.org/torproject.org oneiric main
-> EOF
-$> gpg --keyserver keys.gnupg.net --recv 886DDD89
-$> gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -
-$> sudo apt-get install tor tor-geoipdb
-$> tor --version
-[É]
-Tor version 0.2.2.35 (git-73ff13ab3cc9570d).
-
-StegoTorus:
------------
-
-$> autoreconf -i
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
-
-No package 'libcrypto++' found
-[...]
-$> sudo apt-get install libcrypto++9 libcrypto++9-dbg libcrypto++-dev
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
-
-No package 'zlib' found
-[...]
-$> sudo apt-get install zlib1g-dbg zlib1g-dev
-$> ./configure --disable-integration-tests --enable-silent-rules
-[...]
-configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
-
-No package 'zlib' found
-[...]
-$> sudo find /usr -name zlib.pc
-/usr/lib/i386-linux-gnu/pkgconfig/zlib.pc
-$> echo $PKG_CONFIG_PATH
-
-$> export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig
-$> ./configure --disable-integration-tests --enable-silent-rules
-$> make
-
-
-compiling obfsproxy under Ubuntu 10.04 (DETERlab)
-=================================================
-
-create local disk space:
-
-$> sudo /usr/local/etc/emulab/mkextrafs.pl /mnt
-
-copy source code there to compile:
-
-$> sudo mkdir /mnt/local/alice
-$> sudo chown linda:SAF-DEFIANCE /mnt/local/alice
-$> cd /mnt/local/alice
-$> tar -xzvf ~/src/stegotorus.tar.gz
-etc.
diff --git a/config-aux/cxx_delete_method.m4 b/config-aux/cxx_delete_method.m4
new file mode 100644
index 0000000..2d467e7
--- /dev/null
+++ b/config-aux/cxx_delete_method.m4
@@ -0,0 +1,78 @@
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxx_delete_method.m4
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_DELETE_METHOD
+#
+# DESCRIPTION
+#
+# Check whether the C++11 '= delete' syntax, for suppressing undesired
+# implicit methods, is supported. If it is, the macro DELETE_METHOD is
+# defined to '= delete'; otherwise it is defined to nothing. Thus, you
+# can write
+#
+# class foo {
+# ...
+# private:
+# foo(foo const&) DELETE_METHOD;
+# };
+#
+# to delete the 'foo' copy constructor or fall back to the idiom of
+# a private undefined method if the compiler doesn't support this.
+#
+# Does not test '= delete' on a template specialization.
+# Does not ensure that the compiler is in C++11 mode.
+#
+# LICENSE
+#
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+AC_DEFUN([AX_CXX_DELETE_METHOD], [dnl
+ AC_LANG_ASSERT([C++])
+ # This compilation should succeed...
+ AC_CACHE_CHECK(whether $CXX accepts method deletion,
+ ax_cv_cxx_delete_method_syntax, [
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ struct foo {
+ foo(double);
+ foo(int) = delete;
+ };
+ extern void t(foo const&);
+ void tt(double n) { t(n); }
+ ]])],
+ [ax_cv_cxx_delete_method_syntax=yes],
+ [ax_cv_cxx_delete_method_syntax=no])])
+ # ... and this one should fail.
+ if test x$ax_cv_cxx_delete_method_syntax = xyes; then
+ AC_CACHE_CHECK(whether $CXX enforces method deletion,
+ ax_cv_cxx_delete_method_enforced, [
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ struct foo {
+ foo(double);
+ foo(int) = delete;
+ };
+ extern void t(foo const&);
+ void tt(int n) { t(n); }
+ ]])],
+ [ax_cv_cxx_delete_method_enforced=no],
+ [ax_cv_cxx_delete_method_enforced=yes])])
+ fi
+ if test x$ax_cv_cxx_delete_method_syntax = xyes &&
+ test x$ax_cv_cxx_delete_method_enforced = xyes
+ then
+ AC_DEFINE([DELETE_METHOD], [= delete],
+ [Define as `= delete' if your compiler supports C++11 method
+ deletion, as nothing otherwise.])
+ else
+ AC_DEFINE([DELETE_METHOD], [],
+ [Define as `= delete' if your compiler supports C++11 method
+ deletion, as nothing otherwise.])
+ fi
+])
diff --git a/config-aux/cxx_static_assert.m4 b/config-aux/cxx_static_assert.m4
new file mode 100644
index 0000000..7bf69f8
--- /dev/null
+++ b/config-aux/cxx_static_assert.m4
@@ -0,0 +1,57 @@
+# SYNOPSIS
+#
+# AX_CXX_STATIC_ASSERT
+#
+# DESCRIPTION
+#
+# Detect whether the C++ compiler, in its present operating mode,
+# supports the C++11 'static_assert' construct. If it doesn't,
+# define 'static_assert' as a preprocessor macro which provides
+# more-or-less the same functionality.
+#
+# LICENSE
+#
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 1
+
+AC_DEFUN([AX_CXX_STATIC_ASSERT], [dnl
+ AC_LANG_ASSERT([C++])dnl
+ AC_CACHE_CHECK(whether $CXX accepts static_assert, ax_cv_cxx_static_assert,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
+ template <typename T>
+ struct check
+ { static_assert(sizeof(int) <= sizeof(T), "not big enough"); };
+ check<int> ok;])],
+ [ax_cv_cxx_static_assert=yes], [ax_cv_cxx_static_assert=no])])
+ if test x$ax_cv_cxx_static_assert = xyes; then
+ AC_CACHE_CHECK(whether $CXX enforces static_assert, ax_cv_cxx_static_assert_e,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
+ template <typename T>
+ struct check
+ { static_assert(sizeof(char[2]) <= sizeof(T), "not big enough"); };
+ check<char> bad;])],
+ [ax_cv_cxx_static_assert_e=no], [ax_cv_cxx_static_assert_e=yes])])
+ fi
+ if test x$ax_cv_cxx_static_assert = xyes &&
+ test x$ax_cv_cxx_static_assert_e = xyes; then
+ AC_DEFINE(HAVE_STATIC_ASSERT, 1,
+ [Define to 1 if the C++ compiler supports static_assert.])
+ fi
+ AH_VERBATIM([HAVE_STATIC_ASSERT_],
+[#ifndef HAVE_STATIC_ASSERT
+# define static_assert(expr, msg) typedef char static_assert_id[(expr)?1:-1]
+# ifdef __COUNTER__
+# define static_assert_id static_assert_paste(static_assert_, __COUNTER__)
+# else
+# define static_assert_id static_assert_paste(static_assert_, __LINE__)
+# endif
+# define static_assert_paste(a,b) static_assert_paste_(a,b)
+# define static_assert_paste_(a,b) a##b
+#endif])
+])
diff --git a/config-aux/cxxflags_stdcxx_11.m4 b/config-aux/cxxflags_stdcxx_11.m4
new file mode 100644
index 0000000..7f06ed2
--- /dev/null
+++ b/config-aux/cxxflags_stdcxx_11.m4
@@ -0,0 +1,102 @@
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxxflags_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXXFLAGS_STDCXX_11([ext|noext])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the C++11
+# standard; if necessary, add switches to CXXFLAGS to enable support.
+# The argument, if specified, indicates whether you insist on an extended
+# mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -std=c++11).
+# If neither is specified, you get whatever works, with preference for an
+# extended mode.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz(a)redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 8
+
+m4_define([_AX_CXXFLAGS_STDCXX_11_testbody], [
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+])
+
+AC_DEFUN([AX_CXXFLAGS_STDCXX_11], [dnl
+ m4_if([$1], [], [],
+ [$1], [ext], [],
+ [$1], [noext], [],
+ [m4_fatal([invalid argument `$1' to AX_CXXFLAGS_STDCXX_11])])dnl
+ AC_LANG_ASSERT([C++])dnl
+ ac_success=no
+ AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+ ax_cv_cxx_compile_cxx11,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [ax_cv_cxx_compile_cxx11=yes],
+ [ax_cv_cxx_compile_cxx11=no])])
+ if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+ ac_success=yes
+ fi
+
+ m4_if([$1], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=gnu++11 -std=gnu++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$1], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=c++11 -std=c++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+])
diff --git a/config-aux/maintainer.m4 b/config-aux/maintainer.m4
new file mode 100644
index 0000000..07948a7
--- /dev/null
+++ b/config-aux/maintainer.m4
@@ -0,0 +1,39 @@
+# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
+# From Jim Meyering
+
+# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2011
+# Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 5
+
+# AM_MAINTAINER_MODE([DEFAULT-MODE])
+# ----------------------------------
+# Control maintainer-specific portions of Makefiles.
+# Default is to disable them, unless `enable' is passed literally.
+# For symmetry, `disable' may be passed as well. Anyway, the user
+# can override the default with the --enable/--disable switch.
+AC_DEFUN([AM_MAINTAINER_MODE],
+[m4_case(m4_default([$1], [disable]),
+ [enable], [m4_define([am_maintainer_other], [disable])],
+ [disable], [m4_define([am_maintainer_other], [enable])],
+ [m4_define([am_maintainer_other], [enable])
+ m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
+AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
+ dnl maintainer-mode's default is 'disable' unless 'enable' is passed
+ AC_ARG_ENABLE([maintainer-mode],
+[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
+ (and sometimes confusing) to the casual installer],
+ [USE_MAINTAINER_MODE=$enableval],
+ [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
+ AC_MSG_RESULT([$USE_MAINTAINER_MODE])
+ AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
+ MAINT=$MAINTAINER_MODE_TRUE
+ AC_SUBST([MAINT])dnl
+]
+)
+
+AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
diff --git a/config-aux/pkg.m4 b/config-aux/pkg.m4
new file mode 100644
index 0000000..9a71878
--- /dev/null
+++ b/config-aux/pkg.m4
@@ -0,0 +1,159 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <scott(a)netsplit.com>.
+#
+# This program is free software; you can 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 of the License, or
+# (at your option) any later version.
+#
+# This program 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
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])# PKG_CHECK_MODULES
diff --git a/config-aux/ranlib.m4 b/config-aux/ranlib.m4
new file mode 100644
index 0000000..ce4fe33
--- /dev/null
+++ b/config-aux/ranlib.m4
@@ -0,0 +1,69 @@
+# SYNOPSIS
+#
+# AX_PROG_RANLIB
+#
+# DESCRIPTION
+#
+# In addition to everything AC_PROG_RANLIB does, determine whether it is
+# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
+# the case on most modern systems), reset the RANLIB variable to ':'.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# 'ranlib' may be needed to make it possible for objects that occur
+# later in an archive library to refer to symbols defined by objects
+# earlier in the archive. Therefore, the testing strategy is to
+# compile three small files where A refers to B refers to C, put C and
+# B in an archive *in that order*, and then see if we can link A
+# against the archive.
+
+AC_DEFUN([AX_PROG_RANLIB],
+[AC_CHECK_TOOL([AR], [ar])
+AC_CHECK_TOOL([RANLIB], [ranlib], [:])
+if test x$RANLIB != x:; then
+ AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
+ [AC_LANG_PUSH([C])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int B(void);
+ int main(void) { return B(); }
+ ]])],
+ [cp conftest.$ac_objext conftA.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file A])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ extern int C(void);
+ int B(void) { return C(); }
+ ]])],
+ [cp conftest.$ac_objext conftB.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file B])])
+
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
+ int C(void) { return 0; }
+ ]])],
+ [cp conftest.$ac_objext conftC.$ac_objext],
+ [AC_MSG_ERROR([failed to compile test file C])])
+
+ dnl There is no standard macro for creating an archive.
+ _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
+ AC_MSG_ERROR([failed to create test archive])
+
+ dnl There's no good way to make AC_LINK_IFELSE do what we need.
+ AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=no],
+ [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
+ [ac_cv_prog_RANLIB_necessary=yes],
+ [AC_MSG_ERROR([test link failed with and without ranlib])])])
+
+ rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
+ AC_LANG_POP([C])
+ ])
+ if test $ac_cv_prog_RANLIB_necessary = no; then
+ RANLIB=:
+ fi
+fi
+])
diff --git a/config-aux/system_extensions.m4 b/config-aux/system_extensions.m4
new file mode 100644
index 0000000..46b2f9e
--- /dev/null
+++ b/config-aux/system_extensions.m4
@@ -0,0 +1,81 @@
+# SYNOPSIS
+#
+# AX_SYS_EXTENSIONS
+#
+# DESCRIPTION
+#
+# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
+# does not trigger AC_CHECK_HEADER's backward compatibility mode;
+# does not make use of AC_INCLUDES_DEFAULT;
+# does not define _MINIX.
+#
+# LICENSE
+#
+# Same as Autoconf proper.
+
+# serial 1
+
+# Enable extensions on systems that normally disable them,
+# typically due to standards-conformance issues.
+#
+# Remember that #undef in AH_VERBATIM gets replaced with #define by
+# AC_DEFINE. The goal here is to define all known feature-enabling
+# macros, then, if reports of conflicts are made, disable macros that
+# cause problems on some platforms (such as __EXTENSIONS__).
+AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
+[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
+AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
+AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
+
+ AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
+ if test "$MINIX" = yes; then
+ AC_DEFINE([_POSIX_SOURCE], [1],
+ [Define to 1 if you need to in order for `stat' and other
+ things to work.])
+ AC_DEFINE([_POSIX_1_SOURCE], [2],
+ [Define to 2 if the system does not provide POSIX.1 features
+ except with this defined.])
+ fi
+
+dnl Use a different key than __EXTENSIONS__, as that name broke existing
+dnl configure.ac when using autoheader 2.62.
+ AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
+[/* Enable extensions on AIX 3, Interix. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them. */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris. */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop. */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris. */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+])
+ AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
+ [ac_cv_safe_to_define___extensions__],
+ [AC_COMPILE_IFELSE(
+ dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
+ dnl implies that testing <stdlib.h> is adequate.
+ [AC_LANG_PROGRAM([[
+# define __EXTENSIONS__ 1
+# include <stdlib.h>
+ ]])],
+ [ac_cv_safe_to_define___extensions__=yes],
+ [ac_cv_safe_to_define___extensions__=no])])
+ test $ac_cv_safe_to_define___extensions__ = yes &&
+ AC_DEFINE([__EXTENSIONS__])
+ AC_DEFINE([_ALL_SOURCE])
+ AC_DEFINE([_GNU_SOURCE])
+ AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
+ AC_DEFINE([_TANDEM_SOURCE])
+])# AX_SYS_EXTENSIONS
diff --git a/config-aux/winsock.m4 b/config-aux/winsock.m4
new file mode 100644
index 0000000..fd3d8b5
--- /dev/null
+++ b/config-aux/winsock.m4
@@ -0,0 +1,56 @@
+# Copyright © 2011 Zack Weinberg <zackw(a)panix.com>
+#
+# Copying and distribution of this software, with or without modification,
+# are permitted in any medium without royalty provided the copyright
+# notice and this notice are preserved. This software is offered as-is,
+# without any warranty.
+
+# The socket API requires a special library on Windows, but
+# AC_SEARCH_LIBS cannot be used to find it, because it will
+# mis-declare 'ntohl' on windows and cause the link to fail.
+#
+# This macro sets the substitution @ws2_LIBS@ to "-lws2_32"
+# if you need that, and "" otherwise. It does not provide
+# any #defines for the differences in socket headers between
+# Windows and Unix -- just use #ifdef _WIN32.
+#
+# Implementation note: we use the same _cv_ variable that
+# AC_SEARCH_LIBS would, because the test is what AC_SEARCH_LIBS
+# *should* have done in this situation.
+AC_DEFUN([AX_LIB_WINSOCK2],
+ [AC_CACHE_CHECK([for library containing ntohl], [ac_cv_search_ntohl],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([
+ #ifdef _WIN32
+ #include <winsock2.h>
+ #else
+ #include <arpa/inet.h>
+ #endif
+ ], [
+ return (int)ntohl(42);])
+ ])
+
+ ax_lib_winsock2_save_LIBS="$LIBS"
+ for ac_lib in '' -lws2_32; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=$ac_lib
+ fi
+ LIBS="$ac_lib $ax_lib_winsock2_save_LIBS"
+ AC_LINK_IFELSE([], [AS_VAR_SET([ac_cv_search_ntohl], [$ac_res])])
+ AS_VAR_SET_IF([ac_cv_search_ntohl], [break])
+ done
+ AS_VAR_SET_IF([ac_cv_search_ntohl], ,
+ [AS_VAR_SET([ac_cv_search_ntohl], [no])])
+ rm conftest.$ac_ext
+ LIBS="$ax_lib_winsock2_save_LIBS"
+ ])
+
+ ws32_LIBS=
+ case "$ac_cv_search_ntohl" in
+ no) AC_MSG_ERROR([could not find ntohl]) ;;
+ "none required") ;;
+ *) ws32_LIBS="$ac_cv_search_ntohl"
+ esac
+ AC_SUBST(ws32_LIBS)
+])
diff --git a/configure.ac b/configure.ac
index 4c23af6..0c858dc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -5,6 +5,7 @@ dnl
AC_PREREQ([2.61])dnl Possibly earlier will do, but this is what I have
AC_INIT([stegotorus], [0.0])
AC_CONFIG_SRCDIR([src/main.cc])
+AC_CONFIG_AUX_DIR([config-aux])
AC_LANG([C++])
AM_INIT_AUTOMAKE([foreign nostdinc silent-rules subdir-objects])
AM_MAINTAINER_MODE([enable])
diff --git a/doc/README.Linda b/doc/README.Linda
new file mode 100644
index 0000000..3cb4d2e
--- /dev/null
+++ b/doc/README.Linda
@@ -0,0 +1,117 @@
+compiling stegotorus on Mac OS X 10.6
+=====================================
+
+0) prelims
+
+Install Mac Ports from http://www.macports.org (here v2.0.3).
+$> sudo port selfupdate [for good measure]
+
+ a) autoconf 2.68
+
+$> sudo port install autoconf
+$> autoconf --version
+autoconf (GNU Autoconf) 2.68
+
+ b) automake 1.11
+
+$> sudo port install automake
+$> automake --version
+automake (GNU automake) 1.11.1
+
+ c) pkgconfig
+
+$> sudo port install pkgconfig
+
+ d) openssl >= 1.0.1, libevent-2
+
+$> sudo port install openssl
+$> sudo port install libevent
+
+ e) tor
+
+$> sudo port install tor
+$> tor --version
+[...]
+Tor version 0.2.2.34 (git-c4eae752f0d157ce).
+
+
+1) StegoTorus
+
+$> cd ~/src/DEFIANCE/stegotorus/sri
+$> autoreconf -i
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
+
+No package 'libcrypto++' found
+[...]
+$> sudo cp Desktop/libcrypto++.pc /usr/lib/pkgconfig/
+$> ./configure --disable-integration-tests --enable-silent-rules
+$> make
+
+
+compiling stegotorus under Ubuntu 11.10
+=======================================
+
+$> sudo apt-get install pkg-config libevent-2.0-5 libevent-dev
+
+Tor:
+----
+
+$> sudo cat >> /etc/apt/sources.list <<EOF
+> deb http://deb.torproject.org/torproject.org oneiric main
+> EOF
+$> gpg --keyserver keys.gnupg.net --recv 886DDD89
+$> gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | sudo apt-key add -
+$> sudo apt-get install tor tor-geoipdb
+$> tor --version
+[É]
+Tor version 0.2.2.35 (git-73ff13ab3cc9570d).
+
+StegoTorus:
+-----------
+
+$> autoreconf -i
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (libcrypto++ >= 5.6.0) were not met:
+
+No package 'libcrypto++' found
+[...]
+$> sudo apt-get install libcrypto++9 libcrypto++9-dbg libcrypto++-dev
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
+
+No package 'zlib' found
+[...]
+$> sudo apt-get install zlib1g-dbg zlib1g-dev
+$> ./configure --disable-integration-tests --enable-silent-rules
+[...]
+configure: error: Package requirements (zlib >= 1.2.3.4) were not met:
+
+No package 'zlib' found
+[...]
+$> sudo find /usr -name zlib.pc
+/usr/lib/i386-linux-gnu/pkgconfig/zlib.pc
+$> echo $PKG_CONFIG_PATH
+
+$> export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig
+$> ./configure --disable-integration-tests --enable-silent-rules
+$> make
+
+
+compiling obfsproxy under Ubuntu 10.04 (DETERlab)
+=================================================
+
+create local disk space:
+
+$> sudo /usr/local/etc/emulab/mkextrafs.pl /mnt
+
+copy source code there to compile:
+
+$> sudo mkdir /mnt/local/alice
+$> sudo chown linda:SAF-DEFIANCE /mnt/local/alice
+$> cd /mnt/local/alice
+$> tar -xzvf ~/src/stegotorus.tar.gz
+etc.
diff --git a/m4/cxx_delete_method.m4 b/m4/cxx_delete_method.m4
deleted file mode 100644
index 2d467e7..0000000
--- a/m4/cxx_delete_method.m4
+++ /dev/null
@@ -1,78 +0,0 @@
-# ============================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cxx_delete_method.m4
-# ============================================================================
-#
-# SYNOPSIS
-#
-# AX_CXX_DELETE_METHOD
-#
-# DESCRIPTION
-#
-# Check whether the C++11 '= delete' syntax, for suppressing undesired
-# implicit methods, is supported. If it is, the macro DELETE_METHOD is
-# defined to '= delete'; otherwise it is defined to nothing. Thus, you
-# can write
-#
-# class foo {
-# ...
-# private:
-# foo(foo const&) DELETE_METHOD;
-# };
-#
-# to delete the 'foo' copy constructor or fall back to the idiom of
-# a private undefined method if the compiler doesn't support this.
-#
-# Does not test '= delete' on a template specialization.
-# Does not ensure that the compiler is in C++11 mode.
-#
-# LICENSE
-#
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-AC_DEFUN([AX_CXX_DELETE_METHOD], [dnl
- AC_LANG_ASSERT([C++])
- # This compilation should succeed...
- AC_CACHE_CHECK(whether $CXX accepts method deletion,
- ax_cv_cxx_delete_method_syntax, [
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- struct foo {
- foo(double);
- foo(int) = delete;
- };
- extern void t(foo const&);
- void tt(double n) { t(n); }
- ]])],
- [ax_cv_cxx_delete_method_syntax=yes],
- [ax_cv_cxx_delete_method_syntax=no])])
- # ... and this one should fail.
- if test x$ax_cv_cxx_delete_method_syntax = xyes; then
- AC_CACHE_CHECK(whether $CXX enforces method deletion,
- ax_cv_cxx_delete_method_enforced, [
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- struct foo {
- foo(double);
- foo(int) = delete;
- };
- extern void t(foo const&);
- void tt(int n) { t(n); }
- ]])],
- [ax_cv_cxx_delete_method_enforced=no],
- [ax_cv_cxx_delete_method_enforced=yes])])
- fi
- if test x$ax_cv_cxx_delete_method_syntax = xyes &&
- test x$ax_cv_cxx_delete_method_enforced = xyes
- then
- AC_DEFINE([DELETE_METHOD], [= delete],
- [Define as `= delete' if your compiler supports C++11 method
- deletion, as nothing otherwise.])
- else
- AC_DEFINE([DELETE_METHOD], [],
- [Define as `= delete' if your compiler supports C++11 method
- deletion, as nothing otherwise.])
- fi
-])
diff --git a/m4/cxx_static_assert.m4 b/m4/cxx_static_assert.m4
deleted file mode 100644
index 7bf69f8..0000000
--- a/m4/cxx_static_assert.m4
+++ /dev/null
@@ -1,57 +0,0 @@
-# SYNOPSIS
-#
-# AX_CXX_STATIC_ASSERT
-#
-# DESCRIPTION
-#
-# Detect whether the C++ compiler, in its present operating mode,
-# supports the C++11 'static_assert' construct. If it doesn't,
-# define 'static_assert' as a preprocessor macro which provides
-# more-or-less the same functionality.
-#
-# LICENSE
-#
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 1
-
-AC_DEFUN([AX_CXX_STATIC_ASSERT], [dnl
- AC_LANG_ASSERT([C++])dnl
- AC_CACHE_CHECK(whether $CXX accepts static_assert, ax_cv_cxx_static_assert,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
- template <typename T>
- struct check
- { static_assert(sizeof(int) <= sizeof(T), "not big enough"); };
- check<int> ok;])],
- [ax_cv_cxx_static_assert=yes], [ax_cv_cxx_static_assert=no])])
- if test x$ax_cv_cxx_static_assert = xyes; then
- AC_CACHE_CHECK(whether $CXX enforces static_assert, ax_cv_cxx_static_assert_e,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([dnl
- template <typename T>
- struct check
- { static_assert(sizeof(char[2]) <= sizeof(T), "not big enough"); };
- check<char> bad;])],
- [ax_cv_cxx_static_assert_e=no], [ax_cv_cxx_static_assert_e=yes])])
- fi
- if test x$ax_cv_cxx_static_assert = xyes &&
- test x$ax_cv_cxx_static_assert_e = xyes; then
- AC_DEFINE(HAVE_STATIC_ASSERT, 1,
- [Define to 1 if the C++ compiler supports static_assert.])
- fi
- AH_VERBATIM([HAVE_STATIC_ASSERT_],
-[#ifndef HAVE_STATIC_ASSERT
-# define static_assert(expr, msg) typedef char static_assert_id[(expr)?1:-1]
-# ifdef __COUNTER__
-# define static_assert_id static_assert_paste(static_assert_, __COUNTER__)
-# else
-# define static_assert_id static_assert_paste(static_assert_, __LINE__)
-# endif
-# define static_assert_paste(a,b) static_assert_paste_(a,b)
-# define static_assert_paste_(a,b) a##b
-#endif])
-])
diff --git a/m4/cxxflags_stdcxx_11.m4 b/m4/cxxflags_stdcxx_11.m4
deleted file mode 100644
index 7f06ed2..0000000
--- a/m4/cxxflags_stdcxx_11.m4
+++ /dev/null
@@ -1,102 +0,0 @@
-# ============================================================================
-# http://www.gnu.org/software/autoconf-archive/ax_cxxflags_stdcxx_11.html
-# ============================================================================
-#
-# SYNOPSIS
-#
-# AX_CXXFLAGS_STDCXX_11([ext|noext])
-#
-# DESCRIPTION
-#
-# Check for baseline language coverage in the compiler for the C++11
-# standard; if necessary, add switches to CXXFLAGS to enable support.
-# The argument, if specified, indicates whether you insist on an extended
-# mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. -std=c++11).
-# If neither is specified, you get whatever works, with preference for an
-# extended mode.
-#
-# LICENSE
-#
-# Copyright (c) 2008 Benjamin Kosnik <bkoz(a)redhat.com>
-# Copyright (c) 2012 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 8
-
-m4_define([_AX_CXXFLAGS_STDCXX_11_testbody], [
- template <typename T>
- struct check
- {
- static_assert(sizeof(int) <= sizeof(T), "not big enough");
- };
-
- typedef check<check<bool>> right_angle_brackets;
-
- int a;
- decltype(a) b;
-
- typedef check<int> check_type;
- check_type c;
- check_type&& cr = static_cast<check_type&&>(c);
-])
-
-AC_DEFUN([AX_CXXFLAGS_STDCXX_11], [dnl
- m4_if([$1], [], [],
- [$1], [ext], [],
- [$1], [noext], [],
- [m4_fatal([invalid argument `$1' to AX_CXXFLAGS_STDCXX_11])])dnl
- AC_LANG_ASSERT([C++])dnl
- ac_success=no
- AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
- ax_cv_cxx_compile_cxx11,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [ax_cv_cxx_compile_cxx11=yes],
- [ax_cv_cxx_compile_cxx11=no])])
- if test x$ax_cv_cxx_compile_cxx11 = xyes; then
- ac_success=yes
- fi
-
- m4_if([$1], [noext], [], [dnl
- if test x$ac_success = xno; then
- for switch in -std=gnu++11 -std=gnu++0x; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
- $cachevar,
- [ac_save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXXFLAGS="$ac_save_CXXFLAGS"])
- if eval test x\$$cachevar = xyes; then
- CXXFLAGS="$CXXFLAGS $switch"
- ac_success=yes
- break
- fi
- done
- fi])
-
- m4_if([$1], [ext], [], [dnl
- if test x$ac_success = xno; then
- for switch in -std=c++11 -std=c++0x; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
- $cachevar,
- [ac_save_CXXFLAGS="$CXXFLAGS"
- CXXFLAGS="$CXXFLAGS $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXXFLAGS_STDCXX_11_testbody])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXXFLAGS="$ac_save_CXXFLAGS"])
- if eval test x\$$cachevar = xyes; then
- CXXFLAGS="$CXXFLAGS $switch"
- ac_success=yes
- break
- fi
- done
- fi])
-])
diff --git a/m4/maintainer.m4 b/m4/maintainer.m4
deleted file mode 100644
index 07948a7..0000000
--- a/m4/maintainer.m4
+++ /dev/null
@@ -1,39 +0,0 @@
-# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
-# From Jim Meyering
-
-# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2011
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# serial 5
-
-# AM_MAINTAINER_MODE([DEFAULT-MODE])
-# ----------------------------------
-# Control maintainer-specific portions of Makefiles.
-# Default is to disable them, unless `enable' is passed literally.
-# For symmetry, `disable' may be passed as well. Anyway, the user
-# can override the default with the --enable/--disable switch.
-AC_DEFUN([AM_MAINTAINER_MODE],
-[m4_case(m4_default([$1], [disable]),
- [enable], [m4_define([am_maintainer_other], [disable])],
- [disable], [m4_define([am_maintainer_other], [enable])],
- [m4_define([am_maintainer_other], [enable])
- m4_warn([syntax], [unexpected argument to AM@&t@_MAINTAINER_MODE: $1])])
-AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
- dnl maintainer-mode's default is 'disable' unless 'enable' is passed
- AC_ARG_ENABLE([maintainer-mode],
-[ --][am_maintainer_other][-maintainer-mode am_maintainer_other make rules and dependencies not useful
- (and sometimes confusing) to the casual installer],
- [USE_MAINTAINER_MODE=$enableval],
- [USE_MAINTAINER_MODE=]m4_if(am_maintainer_other, [enable], [no], [yes]))
- AC_MSG_RESULT([$USE_MAINTAINER_MODE])
- AM_CONDITIONAL([MAINTAINER_MODE], [test $USE_MAINTAINER_MODE = yes])
- MAINT=$MAINTAINER_MODE_TRUE
- AC_SUBST([MAINT])dnl
-]
-)
-
-AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
diff --git a/m4/pkg.m4 b/m4/pkg.m4
deleted file mode 100644
index 9a71878..0000000
--- a/m4/pkg.m4
+++ /dev/null
@@ -1,159 +0,0 @@
-# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
-# serial 1 (pkg-config-0.24)
-#
-# Copyright © 2004 Scott James Remnant <scott(a)netsplit.com>.
-#
-# This program is free software; you can 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 of the License, or
-# (at your option) any later version.
-#
-# This program 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
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-#
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# PKG_PROG_PKG_CONFIG([MIN-VERSION])
-# ----------------------------------
-AC_DEFUN([PKG_PROG_PKG_CONFIG],
-[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
-m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
-m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
-AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
-AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
-AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
- AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
-fi
-if test -n "$PKG_CONFIG"; then
- _pkg_min_version=m4_default([$1], [0.9.0])
- AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
- if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
- AC_MSG_RESULT([yes])
- else
- AC_MSG_RESULT([no])
- PKG_CONFIG=""
- fi
-fi[]dnl
-])# PKG_PROG_PKG_CONFIG
-
-# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
-#
-# Check to see whether a particular set of modules exists. Similar
-# to PKG_CHECK_MODULES(), but does not set variables or print errors.
-#
-# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-# only at the first occurence in configure.ac, so if the first place
-# it's called might be skipped (such as if it is within an "if", you
-# have to call PKG_CHECK_EXISTS manually
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_EXISTS],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-if test -n "$PKG_CONFIG" && \
- AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
- m4_default([$2], [:])
-m4_ifvaln([$3], [else
- $3])dnl
-fi])
-
-# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
-# ---------------------------------------------
-m4_define([_PKG_CONFIG],
-[if test -n "$$1"; then
- pkg_cv_[]$1="$$1"
- elif test -n "$PKG_CONFIG"; then
- PKG_CHECK_EXISTS([$3],
- [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
- test "x$?" != "x0" && pkg_failed=yes ],
- [pkg_failed=yes])
- else
- pkg_failed=untried
-fi[]dnl
-])# _PKG_CONFIG
-
-# _PKG_SHORT_ERRORS_SUPPORTED
-# -----------------------------
-AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
- _pkg_short_errors_supported=yes
-else
- _pkg_short_errors_supported=no
-fi[]dnl
-])# _PKG_SHORT_ERRORS_SUPPORTED
-
-
-# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
-# [ACTION-IF-NOT-FOUND])
-#
-#
-# Note that if there is a possibility the first call to
-# PKG_CHECK_MODULES might not happen, you should be sure to include an
-# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
-#
-#
-# --------------------------------------------------------------
-AC_DEFUN([PKG_CHECK_MODULES],
-[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
-AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
-AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
-
-pkg_failed=no
-AC_MSG_CHECKING([for $1])
-
-_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
-_PKG_CONFIG([$1][_LIBS], [libs], [$2])
-
-m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
-and $1[]_LIBS to avoid the need to call pkg-config.
-See the pkg-config man page for more details.])
-
-if test $pkg_failed = yes; then
- AC_MSG_RESULT([no])
- _PKG_SHORT_ERRORS_SUPPORTED
- if test $_pkg_short_errors_supported = yes; then
- $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
- else
- $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
- fi
- # Put the nasty error message in config.log where it belongs
- echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
-
- m4_default([$4], [AC_MSG_ERROR(
-[Package requirements ($2) were not met:
-
-$$1_PKG_ERRORS
-
-Consider adjusting the PKG_CONFIG_PATH environment variable if you
-installed software in a non-standard prefix.
-
-_PKG_TEXT])[]dnl
- ])
-elif test $pkg_failed = untried; then
- AC_MSG_RESULT([no])
- m4_default([$4], [AC_MSG_FAILURE(
-[The pkg-config script could not be found or is too old. Make sure it
-is in your PATH or set the PKG_CONFIG environment variable to the full
-path to pkg-config.
-
-_PKG_TEXT
-
-To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
- ])
-else
- $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
- $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
- AC_MSG_RESULT([yes])
- $3
-fi[]dnl
-])# PKG_CHECK_MODULES
diff --git a/m4/ranlib.m4 b/m4/ranlib.m4
deleted file mode 100644
index ce4fe33..0000000
--- a/m4/ranlib.m4
+++ /dev/null
@@ -1,69 +0,0 @@
-# SYNOPSIS
-#
-# AX_PROG_RANLIB
-#
-# DESCRIPTION
-#
-# In addition to everything AC_PROG_RANLIB does, determine whether it is
-# _necessary_ to run 'ranlib' after 'ar'. If it is unnecessary (which is
-# the case on most modern systems), reset the RANLIB variable to ':'.
-#
-# LICENSE
-#
-# Same as Autoconf proper.
-
-# serial 1
-
-# 'ranlib' may be needed to make it possible for objects that occur
-# later in an archive library to refer to symbols defined by objects
-# earlier in the archive. Therefore, the testing strategy is to
-# compile three small files where A refers to B refers to C, put C and
-# B in an archive *in that order*, and then see if we can link A
-# against the archive.
-
-AC_DEFUN([AX_PROG_RANLIB],
-[AC_CHECK_TOOL([AR], [ar])
-AC_CHECK_TOOL([RANLIB], [ranlib], [:])
-if test x$RANLIB != x:; then
- AC_CACHE_CHECK([whether ranlib is necessary], [ac_cv_prog_RANLIB_necessary],
- [AC_LANG_PUSH([C])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- extern int B(void);
- int main(void) { return B(); }
- ]])],
- [cp conftest.$ac_objext conftA.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file A])])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- extern int C(void);
- int B(void) { return C(); }
- ]])],
- [cp conftest.$ac_objext conftB.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file B])])
-
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([[
- int C(void) { return 0; }
- ]])],
- [cp conftest.$ac_objext conftC.$ac_objext],
- [AC_MSG_ERROR([failed to compile test file C])])
-
- dnl There is no standard macro for creating an archive.
- _AC_DO([$AR cru conftest.a conftC.$ac_objext conftB.$ac_objext]) ||
- AC_MSG_ERROR([failed to create test archive])
-
- dnl There's no good way to make AC_LINK_IFELSE do what we need.
- AS_IF([_AC_DO([$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
- [ac_cv_prog_RANLIB_necessary=no],
- [AS_IF([_AC_DO([$RANLIB conftest.a && $CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftA.$ac_objext conftest.a >&AS_MESSAGE_LOG_FD])],
- [ac_cv_prog_RANLIB_necessary=yes],
- [AC_MSG_ERROR([test link failed with and without ranlib])])])
-
- rm -f conftest$ac_exeext conft[ABC].$ac_objext conftest.a
- AC_LANG_POP([C])
- ])
- if test $ac_cv_prog_RANLIB_necessary = no; then
- RANLIB=:
- fi
-fi
-])
diff --git a/m4/system_extensions.m4 b/m4/system_extensions.m4
deleted file mode 100644
index 46b2f9e..0000000
--- a/m4/system_extensions.m4
+++ /dev/null
@@ -1,81 +0,0 @@
-# SYNOPSIS
-#
-# AX_SYS_EXTENSIONS
-#
-# DESCRIPTION
-#
-# Functionally equivalent to the stock AC_USE_SYSTEM_EXTENSIONS, but:
-# does not trigger AC_CHECK_HEADER's backward compatibility mode;
-# does not make use of AC_INCLUDES_DEFAULT;
-# does not define _MINIX.
-#
-# LICENSE
-#
-# Same as Autoconf proper.
-
-# serial 1
-
-# Enable extensions on systems that normally disable them,
-# typically due to standards-conformance issues.
-#
-# Remember that #undef in AH_VERBATIM gets replaced with #define by
-# AC_DEFINE. The goal here is to define all known feature-enabling
-# macros, then, if reports of conflicts are made, disable macros that
-# cause problems on some platforms (such as __EXTENSIONS__).
-AC_DEFUN_ONCE([AX_SYS_EXTENSIONS],
-[AC_BEFORE([$0], [AC_COMPILE_IFELSE])dnl
-AC_BEFORE([$0], [AC_RUN_IFELSE])dnl
-AC_PROVIDE([AC_USE_SYSTEM_EXTENSIONS])dnl Suppress the stock macro if used.
-
- AC_CHECK_HEADER([minix/config.h], [MINIX=yes], [MINIX=], [/**/])
- if test "$MINIX" = yes; then
- AC_DEFINE([_POSIX_SOURCE], [1],
- [Define to 1 if you need to in order for `stat' and other
- things to work.])
- AC_DEFINE([_POSIX_1_SOURCE], [2],
- [Define to 2 if the system does not provide POSIX.1 features
- except with this defined.])
- fi
-
-dnl Use a different key than __EXTENSIONS__, as that name broke existing
-dnl configure.ac when using autoheader 2.62.
- AH_VERBATIM([USE_SYSTEM_EXTENSIONS],
-[/* Enable extensions on AIX 3, Interix. */
-#ifndef _ALL_SOURCE
-# undef _ALL_SOURCE
-#endif
-/* Enable GNU extensions on systems that have them. */
-#ifndef _GNU_SOURCE
-# undef _GNU_SOURCE
-#endif
-/* Enable threading extensions on Solaris. */
-#ifndef _POSIX_PTHREAD_SEMANTICS
-# undef _POSIX_PTHREAD_SEMANTICS
-#endif
-/* Enable extensions on HP NonStop. */
-#ifndef _TANDEM_SOURCE
-# undef _TANDEM_SOURCE
-#endif
-/* Enable general extensions on Solaris. */
-#ifndef __EXTENSIONS__
-# undef __EXTENSIONS__
-#endif
-])
- AC_CACHE_CHECK([whether it is safe to define __EXTENSIONS__],
- [ac_cv_safe_to_define___extensions__],
- [AC_COMPILE_IFELSE(
- dnl http://lists.gnu.org/archive/html/bug-gnulib/2006-02/msg00002.html
- dnl implies that testing <stdlib.h> is adequate.
- [AC_LANG_PROGRAM([[
-# define __EXTENSIONS__ 1
-# include <stdlib.h>
- ]])],
- [ac_cv_safe_to_define___extensions__=yes],
- [ac_cv_safe_to_define___extensions__=no])])
- test $ac_cv_safe_to_define___extensions__ = yes &&
- AC_DEFINE([__EXTENSIONS__])
- AC_DEFINE([_ALL_SOURCE])
- AC_DEFINE([_GNU_SOURCE])
- AC_DEFINE([_POSIX_PTHREAD_SEMANTICS])
- AC_DEFINE([_TANDEM_SOURCE])
-])# AX_SYS_EXTENSIONS
diff --git a/m4/winsock.m4 b/m4/winsock.m4
deleted file mode 100644
index fd3d8b5..0000000
--- a/m4/winsock.m4
+++ /dev/null
@@ -1,56 +0,0 @@
-# Copyright © 2011 Zack Weinberg <zackw(a)panix.com>
-#
-# Copying and distribution of this software, with or without modification,
-# are permitted in any medium without royalty provided the copyright
-# notice and this notice are preserved. This software is offered as-is,
-# without any warranty.
-
-# The socket API requires a special library on Windows, but
-# AC_SEARCH_LIBS cannot be used to find it, because it will
-# mis-declare 'ntohl' on windows and cause the link to fail.
-#
-# This macro sets the substitution @ws2_LIBS@ to "-lws2_32"
-# if you need that, and "" otherwise. It does not provide
-# any #defines for the differences in socket headers between
-# Windows and Unix -- just use #ifdef _WIN32.
-#
-# Implementation note: we use the same _cv_ variable that
-# AC_SEARCH_LIBS would, because the test is what AC_SEARCH_LIBS
-# *should* have done in this situation.
-AC_DEFUN([AX_LIB_WINSOCK2],
- [AC_CACHE_CHECK([for library containing ntohl], [ac_cv_search_ntohl],
- [AC_LANG_CONFTEST([AC_LANG_PROGRAM([
- #ifdef _WIN32
- #include <winsock2.h>
- #else
- #include <arpa/inet.h>
- #endif
- ], [
- return (int)ntohl(42);])
- ])
-
- ax_lib_winsock2_save_LIBS="$LIBS"
- for ac_lib in '' -lws2_32; do
- if test -z "$ac_lib"; then
- ac_res="none required"
- else
- ac_res=$ac_lib
- fi
- LIBS="$ac_lib $ax_lib_winsock2_save_LIBS"
- AC_LINK_IFELSE([], [AS_VAR_SET([ac_cv_search_ntohl], [$ac_res])])
- AS_VAR_SET_IF([ac_cv_search_ntohl], [break])
- done
- AS_VAR_SET_IF([ac_cv_search_ntohl], ,
- [AS_VAR_SET([ac_cv_search_ntohl], [no])])
- rm conftest.$ac_ext
- LIBS="$ax_lib_winsock2_save_LIBS"
- ])
-
- ws32_LIBS=
- case "$ac_cv_search_ntohl" in
- no) AC_MSG_ERROR([could not find ntohl]) ;;
- "none required") ;;
- *) ws32_LIBS="$ac_cv_search_ntohl"
- esac
- AC_SUBST(ws32_LIBS)
-])
1
0

[stegotorus/master] Add ECDH implementation to crypt.cc/h (no tests yet)
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 0775073adf3b2b13748af23516080cdfc3a30ee2
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Tue Jun 5 16:22:10 2012 -0700
Add ECDH implementation to crypt.cc/h (no tests yet)
---
src/crypt.cc | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/crypt.h | 34 +++++++++++++++++
2 files changed, 149 insertions(+), 0 deletions(-)
diff --git a/src/crypt.cc b/src/crypt.cc
index d4af5e0..8c7a6b9 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -8,8 +8,10 @@
#include <openssl/engine.h>
#include <openssl/err.h>
+#include <openssl/ecdh.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
+#include <openssl/objects.h>
static bool crypto_initialized = false;
static bool crypto_errs_initialized = false;
@@ -410,6 +412,107 @@ gcm_decryptor_impl::decrypt(uint8_t *out, const uint8_t *in, size_t inlen,
return 0;
}
+// We use the slightly lower-level EC_* / ECDH_* routines for
+// ecdh_message, instead of the EVP_PKEY_* routines, because we don't
+// need algorithmic agility, and it means we only have to puzzle out
+// one layer of completely undocumented APIs instead of two.
+namespace {
+ struct ecdh_message_impl : ecdh_message
+ {
+ EC_KEY *priv;
+ BN_CTX *ctx;
+ ecdh_message_impl(); // generate keypair from randomness
+
+ virtual ~ecdh_message_impl();
+ virtual void encode(uint8_t *xcoord_out) const;
+ virtual int combine(const uint8_t *other, uint8_t *secret_out) const;
+ };
+}
+
+ecdh_message_impl::ecdh_message_impl()
+ : priv(EC_KEY_new_by_curve_name(NID_secp224r1)),
+ ctx(BN_CTX_new())
+{
+ if (!priv || !ctx)
+ log_crypto_abort("ecdh_message::allocate data");
+ if (!EC_KEY_generate_key(priv))
+ log_crypto_abort("ecdh_message::generate priv");
+}
+
+/* static */ ecdh_message *
+ecdh_message::generate()
+{
+ REQUIRE_INIT_CRYPTO();
+ return new ecdh_message_impl();
+}
+
+ecdh_message::~ecdh_message() {}
+ecdh_message_impl::~ecdh_message_impl()
+{
+ EC_KEY_free(priv);
+ BN_CTX_free(ctx);
+}
+
+void
+ecdh_message_impl::encode(uint8_t *xcoord_out) const
+{
+ const EC_POINT *pub = EC_KEY_get0_public_key(priv);
+ const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ if (!pub || !grp)
+ log_crypto_abort("ecdh_message_encode::extract pubkey");
+
+ BIGNUM *x = BN_new();
+ if (!x)
+ log_crypto_abort("ecdh_message_encode::allocate data");
+
+ if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, ctx))
+ log_crypto_abort("ecdh_message_encode::extract x-coordinate");
+
+ size_t sbytes = BN_num_bytes(x);
+ log_assert(sbytes <= EC_P224_LEN);
+ if (sbytes < EC_P224_LEN) {
+ memset(xcoord_out, 0, EC_P224_LEN - sbytes);
+ sbytes += EC_P224_LEN - sbytes;
+ }
+ size_t wbytes = BN_bn2bin(x, xcoord_out);
+ log_assert(sbytes == wbytes);
+
+ BN_free(x);
+}
+
+int
+ecdh_message_impl::combine(const uint8_t *xcoord_other,
+ uint8_t *secret_out) const
+{
+ const EC_GROUP *grp = EC_KEY_get0_group(priv);
+ EC_POINT *pub = EC_POINT_new(grp);
+ if (!grp || !pub)
+ log_crypto_abort("ecdh_message_combine::allocate data");
+
+ int rv = -1;
+ BIGNUM *x = BN_bin2bn(xcoord_other, EC_P224_LEN, 0);
+ if (!x) {
+ log_crypto_warn("ecdh_message_combine::decode their x-coordinate");
+ goto done;
+ }
+
+ if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, ctx)) {
+ log_crypto_warn("ecdh_message_combine::recover their point");
+ goto done;
+ }
+
+ if (!ECDH_compute_key(secret_out, EC_P224_LEN, pub, priv, 0)) {
+ log_crypto_warn("ecdh_message_combine::compute shared secret");
+ goto done;
+ }
+
+ rv = 0;
+ done:
+ BN_free(x);
+ EC_POINT_free(pub);
+ return rv;
+}
+
namespace {
struct key_generator_impl : key_generator
{
@@ -462,6 +565,18 @@ key_generator::from_random_secret(const uint8_t *key, size_t klen,
}
key_generator *
+key_generator::from_ecdh(const ecdh_message *mine, const uint8_t *theirs,
+ const uint8_t *salt, size_t slen,
+ const uint8_t *ctxt, size_t clen)
+{
+ MemBlock ss(EC_P224_LEN);
+ if (mine->combine(theirs, ss))
+ return 0;
+
+ return from_random_secret(ss, EC_P224_LEN, salt, slen, ctxt, clen);
+}
+
+key_generator *
key_generator::from_passphrase(const uint8_t *phra, size_t plen,
const uint8_t *salt, size_t slen,
const uint8_t *ctxt, size_t clen)
diff --git a/src/crypt.h b/src/crypt.h
index 4da3309..35e3e37 100644
--- a/src/crypt.h
+++ b/src/crypt.h
@@ -8,6 +8,7 @@
const size_t AES_BLOCK_LEN = 16;
const size_t GCM_TAG_LEN = 16;
const size_t SHA256_LEN = 32;
+const size_t EC_P224_LEN = 28;
/**
* Initialize cryptography library. Must be called before anything that
@@ -140,6 +141,31 @@ private:
gcm_decryptor& operator=(const gcm_decryptor&) DELETE_METHOD;
};
+/** Encapsulation of an elliptic curve Diffie-Hellman message
+ (we use NIST P-224). */
+struct ecdh_message
+{
+ ecdh_message() {}
+ virtual ~ecdh_message();
+
+ /** Generate a new Diffie-Hellman message from randomness. */
+ static ecdh_message *generate();
+
+ /** Encode a Diffie-Hellman message to the wire format. This
+ produces only the x-coordinate of the chosen curve point.
+ The argument must point to EC_P224_LEN bytes of buffer space. */
+ virtual void encode(uint8_t *xcoord_out) const = 0;
+
+ /** Combine our message with the wire-format message sent by our
+ peer, and produce the raw ECDH shared secret. |xcoord_other|
+ must point to EC_P224_LEN bytes of data, and |secret_out| must
+ point to the same quantity of buffer space. Normally you should
+ use key_generator::from_ecdh instead of calling this
+ directly. */
+ virtual int combine(const uint8_t *xcoord_other, uint8_t *secret_out)
+ const = 0;
+};
+
/** Generate keying material from an initial key of some kind, a salt
value, and a context value, all of which are formally bitstrings.
See http://tools.ietf.org/html/rfc5869 for the requirements on the
@@ -166,6 +192,14 @@ struct key_generator
const uint8_t *salt, size_t slen,
const uint8_t *ctxt, size_t clen);
+ /** Construct a key generator from two (elliptic curve) Diffie-Hellman
+ messages. The salt and context arguments are the same as for
+ from_random_secret. */
+ static key_generator *from_ecdh(const ecdh_message *mine,
+ const uint8_t *theirs,
+ const uint8_t *salt, size_t slen,
+ const uint8_t *ctxt, size_t clen);
+
/** Write LEN bytes of key material to BUF. May be called
repeatedly. Note that HKDF has a hard upper limit on the total
amount of key material it can generate. The return value is
1
0

[stegotorus/master] Use one global BN_CTX rather than allocating one per ECDH object.
by zwol@torproject.org 20 Jul '12
by zwol@torproject.org 20 Jul '12
20 Jul '12
commit 379b9bae47b7671e90cdf9f8cd769630a4e4c4ca
Author: Zack Weinberg <zackw(a)cmu.edu>
Date: Thu Jun 7 14:51:22 2012 -0700
Use one global BN_CTX rather than allocating one per ECDH object.
---
src/audit-globals.sh | 1 +
src/crypt.cc | 33 +++++++++++++++++----------------
2 files changed, 18 insertions(+), 16 deletions(-)
diff --git a/src/audit-globals.sh b/src/audit-globals.sh
index 025549f..27cab3a 100644
--- a/src/audit-globals.sh
+++ b/src/audit-globals.sh
@@ -35,6 +35,7 @@ sed '
/^connections last_ckt_serial$/d
/^connections last_conn_serial$/d
/^connections shutting_down$/d
+ /^crypt bctx$/d
/^crypt crypto_initialized$/d
/^crypt crypto_errs_initialized$/d
/^main allow_kq$/d
diff --git a/src/crypt.cc b/src/crypt.cc
index ec59511..1110d0b 100644
--- a/src/crypt.cc
+++ b/src/crypt.cc
@@ -15,6 +15,7 @@
static bool crypto_initialized = false;
static bool crypto_errs_initialized = false;
+static BN_CTX *bctx = 0;
#define REQUIRE_INIT_CRYPTO() \
log_assert(crypto_initialized)
@@ -28,19 +29,23 @@ init_crypto()
CRYPTO_set_mem_functions(xmalloc, xrealloc, free);
ENGINE_load_builtin_engines();
ENGINE_register_all_complete();
+ bctx = BN_CTX_new();
+ if (!bctx)
+ log_crypto_abort("initialization");
- // we don't need to call OpenSSL_add_all_algorithms, since we never
+ // We don't need to call OpenSSL_add_all_algorithms, since we never
// look up ciphers by textual name.
}
void
free_crypto()
{
- // we don't need to call EVP_cleanup, since we never called
- // OpenSSL_add_all_algorithms.
-
- if (crypto_initialized)
+ if (crypto_initialized) {
+ // We don't need to call EVP_cleanup, since we never called
+ // OpenSSL_add_all_algorithms.
+ BN_CTX_free(bctx);
ENGINE_cleanup();
+ }
if (crypto_errs_initialized)
ERR_free_strings();
}
@@ -420,7 +425,6 @@ namespace {
struct ecdh_message_impl : ecdh_message
{
EC_KEY *key;
- BN_CTX *ctx;
ecdh_message_impl();
ecdh_message_impl(const uint8_t *secret);
@@ -433,21 +437,19 @@ namespace {
}
ecdh_message_impl::ecdh_message_impl()
- : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
- ctx(BN_CTX_new())
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1))
{
- if (!key || !ctx)
+ if (!key)
log_crypto_abort("ecdh_message::allocate data");
if (!EC_KEY_generate_key(key))
log_crypto_abort("ecdh_message::generate key");
}
ecdh_message_impl::ecdh_message_impl(const uint8_t *secret)
- : key(EC_KEY_new_by_curve_name(NID_secp224r1)),
- ctx(BN_CTX_new())
+ : key(EC_KEY_new_by_curve_name(NID_secp224r1))
{
BIGNUM *sb = BN_bin2bn(secret, EC_P224_LEN, 0);
- if (!key || !ctx || !sb)
+ if (!key || !sb)
log_crypto_abort("ecdh_message::allocate data");
if (!EC_KEY_set_private_key(key, sb))
@@ -476,7 +478,7 @@ ecdh_message_impl::regen_pubkey()
if (!pub)
return -1;
- if (!EC_POINT_mul(grp, pub, priv, 0, 0, ctx))
+ if (!EC_POINT_mul(grp, pub, priv, 0, 0, bctx))
return -1;
EC_KEY_set_public_key(key, pub);
@@ -510,7 +512,6 @@ ecdh_message::~ecdh_message() {}
ecdh_message_impl::~ecdh_message_impl()
{
EC_KEY_free(key);
- BN_CTX_free(ctx);
}
void
@@ -525,7 +526,7 @@ ecdh_message_impl::encode(uint8_t *xcoord_out) const
if (!x)
log_crypto_abort("ecdh_message_encode::allocate data");
- if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, ctx))
+ if (!EC_POINT_get_affine_coordinates_GFp(grp, pub, x, 0, bctx))
log_crypto_abort("ecdh_message_encode::extract x-coordinate");
size_t sbytes = BN_num_bytes(x);
@@ -559,7 +560,7 @@ ecdh_message_impl::combine(const uint8_t *xcoord_other,
goto done;
}
- if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, ctx)) {
+ if (!EC_POINT_set_compressed_coordinates_GFp(grp, pub, x, 0, bctx)) {
log_crypto_warn("ecdh_message_combine::recover their point");
goto done;
}
1
0