tor-commits
Threads by month
- ----- 2026 -----
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- 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
- 1 participants
- 214711 discussions
[metrics-tasks/master] Add code to extract and transform dirreqs from the metrics-web database.
by karsten@torproject.org 25 Mar '11
by karsten@torproject.org 25 Mar '11
25 Mar '11
commit 34ff5894093706ceee424968c1ed18cd729ed7d9
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri Mar 25 13:45:27 2011 +0100
Add code to extract and transform dirreqs from the metrics-web database.
---
task-2718/.gitignore | 2 +-
task-2718/README | 22 ++++++++++++++++++++++
task-2718/convert-dirreqs-sql.R | 8 ++++++++
3 files changed, 31 insertions(+), 1 deletions(-)
diff --git a/task-2718/.gitignore b/task-2718/.gitignore
index 673fa5f..917bb1b 100644
--- a/task-2718/.gitignore
+++ b/task-2718/.gitignore
@@ -1,3 +1,3 @@
-direct-users.csv
+*.csv
*.pdf
diff --git a/task-2718/README b/task-2718/README
index 807142a..8c60847 100644
--- a/task-2718/README
+++ b/task-2718/README
@@ -3,3 +3,25 @@ Here's how you run the censorship detector prototype:
$ wget https://metrics.torproject.org/csv/direct-users.csv
$ R --slave -f detect-censorship.R
+-------------------------------------------------------------------------
+
+Extracting raw directory requests from the metrics-web database:
+
+- Export dirreq_stats table from the metrics-web database via psql:
+
+ # \f ','
+ # \a
+ # \t
+ # \o dirreqs-sql.csv
+ # SELECT * FROM dirreq_stats ORDER BY statsend;
+ # \o
+ # \t
+ # \a
+
+- Transform the huge (!) CSV file (104M) from long to wide format. Note
+ that this takes a while:
+
+ $ R --slave -f convert-dirreqs-sql.R
+
+- The result is in dirreqs.csv (8.8M).
+
diff --git a/task-2718/convert-dirreqs-sql.R b/task-2718/convert-dirreqs-sql.R
new file mode 100644
index 0000000..e330307
--- /dev/null
+++ b/task-2718/convert-dirreqs-sql.R
@@ -0,0 +1,8 @@
+library(ggplot2)
+data <- read.csv("dirreqs-sql.csv", header = FALSE)
+data <- data.frame(fingerprint = data$V1, statsend = data$V2,
+ seconds = data$V3, country = data$V4, requests = data$V5)
+data <- cast(data, fingerprint + statsend + seconds ~ country,
+ value = "requests")
+write.csv(data, file = "dirreqs.csv", quote = FALSE, row.names = FALSE)
+
1
0
r24434: {website} move robert and chiiph to the core people page (website/trunk/about/en)
by Roger Dingledine 25 Mar '11
by Roger Dingledine 25 Mar '11
25 Mar '11
Author: arma
Date: 2011-03-25 09:48:18 +0000 (Fri, 25 Mar 2011)
New Revision: 24434
Modified:
website/trunk/about/en/corepeople.wml
website/trunk/about/en/volunteers.wml
Log:
move robert and chiiph to the core people page
Modified: website/trunk/about/en/corepeople.wml
===================================================================
--- website/trunk/about/en/corepeople.wml 2011-03-25 02:30:48 UTC (rev 24433)
+++ website/trunk/about/en/corepeople.wml 2011-03-25 09:48:18 UTC (rev 24434)
@@ -136,6 +136,10 @@
Tor network and measures various properties and
behaviors. Developer and maintainer of <a href="<page
torbutton/index>">Torbutton</a>.</dd>
+ <dt>Robert Ransom</dt>
+ <dd>Bug catcher and immensely helpful on irc and the
+ email lists. Looking into hidden service performance and
+ robustness.</dd>
<dt>Karen Reilly, Development Director</dt>
<dd>Responsible for fundraising, advocacy, general marketing,
policy outreach programs for Tor. She is also available to
@@ -160,6 +164,9 @@
<dd>Works on the artwork and design for various projects,
annual reports, and brochures. His other work can be found at
<a href="http://jmtodaro.com/">http://jmtodaro.com/</a>.</dd>
+ <dt>Tomás Touceda</dt>
+ <dd>Maintenance and new development for Vidalia.</dd>
+
</dl>
</div>
<!-- END MAINCOL -->
Modified: website/trunk/about/en/volunteers.wml
===================================================================
--- website/trunk/about/en/volunteers.wml 2011-03-25 02:30:48 UTC (rev 24433)
+++ website/trunk/about/en/volunteers.wml 2011-03-25 09:48:18 UTC (rev 24434)
@@ -36,8 +36,6 @@
defenses, and resource management, especially for hidden services.</dd>
<dt>Martin Peck</dt><dd>Working on a VM-based transparent
proxying approach for Tor clients on Windows.</dd>
-<dt>Robert Ransom</dt><dd>Bug catcher and immensely helpful on irc and the
-email lists</dd>
<dt>rovv (a pseudonym -- he's managed to stay anonymous even from
us!)</dt><dd>The most dedicated bug reporter we've ever heard from. He
must read Tor source code every day over breakfast.</dd>
@@ -46,8 +44,6 @@
href="<wiki>TransparentProxy">transparent
proxy</a>. Also maintains the <a
href="http://p56soo2ibjkx23xo.onion/">TorDNSEL code</a>.</dd>
-<dt>Tomás Touceda</dt><dd>Fantastic developer involved with the Vidalia
-project</dd>
<dt>Kyle Williams</dt><dd>Developer for
JanusVM, a VMWare-based
transparent Tor proxy that makes Tor easier to set up and use.</dd>
1
0
[metrics-tasks/master] Add George's censorship detector script.
by karsten@torproject.org 25 Mar '11
by karsten@torproject.org 25 Mar '11
25 Mar '11
commit f5d257dff6af41dbbe33ab20c5bbb218a38c8cd8
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Fri Mar 25 10:29:38 2011 +0100
Add George's censorship detector script.
---
task-2718/detector.py | 306 +++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 306 insertions(+), 0 deletions(-)
diff --git a/task-2718/detector.py b/task-2718/detector.py
new file mode 100644
index 0000000..0370d02
--- /dev/null
+++ b/task-2718/detector.py
@@ -0,0 +1,306 @@
+## Copyright (c) 2011 George Danezis <gdane(a)microsoft.com>
+##
+## All rights reserved.
+##
+## Redistribution and use in source and binary forms, with or without
+## modification, are permitted (subject to the limitations in the
+## disclaimer below) provided that the following conditions are met:
+##
+## * Redistributions of source code must retain the above copyright
+## notice, this list of conditions and the following disclaimer.
+##
+## * Redistributions in binary form must reproduce the above copyright
+## notice, this list of conditions and the following disclaimer in the
+## documentation and/or other materials provided with the
+## distribution.
+##
+## * Neither the name of <Owner Organization> nor the names of its
+## contributors may be used to endorse or promote products derived
+## from this software without specific prior written permission.
+##
+## NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
+## GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT
+## HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
+## WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+## MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+## DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+## LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+## CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+## SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+## BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+## WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+## OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+## IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+## (Clear BSD license: http://labs.metacarta.com/license-explanation.html#license)
+
+## This script reads a .csv file of the number of Tor users and finds
+## anomalies that might be indicative of censorship.
+
+# Dep: matplotlib
+from pylab import *
+import matplotlib
+
+# Dep: numpy
+import numpy
+
+# Dep: scipy
+import scipy.stats
+from scipy.stats.distributions import norm
+from scipy.stats.distributions import poisson
+
+# Std lib
+from datetime import date
+from datetime import timedelta
+import os.path
+
+days = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
+
+# read the .csv file
+class torstatstore:
+ def __init__(self, file_name):
+ f = file(file_name)
+ country_codes = f.readline()
+ country_codes = country_codes.strip().split(",")
+
+ store = {}
+ MAX_INDEX = 0
+ for i, line in enumerate(f):
+ MAX_INDEX += 1
+ line_parsed = line.strip().split(",")
+ for j, (ccode, val) in enumerate(zip(country_codes,line_parsed)):
+ processed_val = None
+ if ccode == "date":
+ try:
+ year, month, day = int(val[:4]), int(val[5:7]), int(val[8:10])
+ processed_val = date(year, month, day)
+ except Exception, e:
+ print "Parsing error (ignoring line %s):" % j
+ print "%s" % val,e
+ break
+
+ elif val != "NA":
+ processed_val = int(val)
+ store[(ccode, i)] = processed_val
+
+ # min and max
+ date_min = store[("date", 0)]
+ date_max = store[("date", i)]
+
+ all_dates = []
+ d = date_min
+ dt = timedelta(days=1)
+ while d <= date_max:
+ all_dates += [d]
+ d = d + dt
+
+ # Save for later
+ self.store = store
+ self.all_dates = all_dates
+ self.country_codes = country_codes
+ self.MAX_INDEX = MAX_INDEX
+ self.date_min = date_min
+ self.date_max = date_max
+
+ def get_country_series(self, ccode):
+ assert ccode in self.country_codes
+ series = {}
+ for d in self.all_dates:
+ series[d] = None
+ for i in range(self.MAX_INDEX):
+ series[self.store[("date", i)]] = self.store[(ccode, i)]
+ sx = []
+ for d in self.all_dates:
+ sx += [series[d]]
+ return sx
+
+ def get_largest(self, number):
+ exclude = set(["all", "??", "date"])
+ l = [(self.store[(c, self.MAX_INDEX-1)], c) for c in self.country_codes if c not in exclude]
+ l.sort()
+ l.reverse()
+ return l[:number]
+
+ def get_largest_locations(self, number):
+ l = self.get_largest(number)
+ res = {}
+ for _, ccode in l[:number]:
+ res[ccode] = self.get_country_series(ccode)
+ return res
+
+# Computes the difference between today and a number of days in the past
+def n_day_rel(series, days):
+ rel = []
+ for i, v in enumerate(series):
+ if series[i] is None:
+ rel += [None]
+ continue
+
+ if i - days < 0 or series[i-days] is None or series[i-days] == 0:
+ rel += [None]
+ else:
+ rel += [ float(series[i]) / series[i-days]]
+ return rel
+
+# Main model: computes the expected min / max range of number of users
+def make_tendencies_minmax(l, INTERVAL = 1):
+ lminus1 = dict([(ccode, n_day_rel(l[ccode], INTERVAL)) for ccode in l])
+ c = lminus1[lminus1.keys()[0]]
+ dists = []
+ minx = []
+ maxx = []
+ for i in range(len(c)):
+ vals = [lminus1[ccode][i] for ccode in lminus1.keys() if lminus1[ccode][i] != None]
+ if len(vals) < 8:
+ dists += [None]
+ minx += [None]
+ maxx += [None]
+ else:
+ vals.sort()
+ median = vals[len(vals)/2]
+ q1 = vals[len(vals)/4]
+ q2 = vals[(3*len(vals))/4]
+ qd = q2 - q1
+ vals = [v for v in vals if median - qd*4 < v and v < median + qd*4]
+ if len(vals) < 8:
+ dists += [None]
+ minx += [None]
+ maxx += [None]
+ continue
+ mu, signma = norm.fit(vals)
+ dists += [(mu, signma)]
+ maxx += [norm.ppf(0.9999, mu, signma)]
+ minx += [norm.ppf(1 - 0.9999, mu, signma)]
+ ## print minx[-1], maxx[-1]
+ return minx, maxx
+
+# Makes pretty plots
+def raw_plot(series, minc, maxc, labels, xtitle):
+ assert len(xtitle) == 3
+ fname, stitle, slegend = xtitle
+
+ font = {'family' : 'Bitstream Vera Sans',
+ 'weight' : 'normal',
+ 'size' : 8}
+ matplotlib.rc('font', **font)
+
+ ylim( (-max(series)*0.1, max(series)*1.1) )
+ plot(labels, series, linewidth=1.0, label="Users")
+
+ wherefill = []
+ for mm,mx in zip(minc, maxc):
+ wherefill += [not (mm == None and mx == None)]
+ assert mm < mx or (mm == None and mx == None)
+
+ fill_between(labels, minc, maxc, where=wherefill, color="gray", label="Prediction")
+
+ vdown = []
+ vup = []
+ for i,v in enumerate(series):
+ if minc[i] != None and v < minc[i]:
+ vdown += [v]
+ vup += [None]
+ elif maxc[i] != None and v > maxc[i]:
+ vdown += [None]
+ vup += [v]
+ else:
+ vup += [None]
+ vdown += [None]
+
+ plot(labels, vdown, 'o', ms=10, lw=2, alpha=0.5, mfc='orange', label="Downturns")
+ plot(labels, vup, 'o', ms=10, lw=2, alpha=0.5, mfc='green', label="Upturns")
+
+ legend(loc=2)
+
+ xlabel('Time (days)')
+ ylabel('Users')
+ title(stitle)
+ grid(True)
+ F = gcf()
+
+ F.set_size_inches(10,5)
+ F.savefig(fname, format="png", dpi = (150))
+ close()
+
+def absolute_plot(series, minc, maxc, labels,INTERVAL, xtitle):
+ in_minc = []
+ in_maxc = []
+ for i, v in enumerate(series):
+ if i > 0 and i - INTERVAL >= 0 and series[i] != None and series[i-INTERVAL] != None and series[i-INTERVAL] != 0 and minc[i]!= None and maxc[i]!= None:
+ in_minc += [minc[i] * poisson.ppf(1-0.9999, series[i-INTERVAL])]
+ in_maxc += [maxc[i] * poisson.ppf(0.9999, series[i-INTERVAL])]
+ if not in_minc[-1] < in_maxc[-1]:
+ print in_minc[-1], in_maxc[-1], series[i-INTERVAL], minc[i], maxc[i]
+ assert in_minc[-1] < in_maxc[-1]
+ else:
+ in_minc += [None]
+ in_maxc += [None]
+ raw_plot(series, in_minc, in_maxc, labels, xtitle)
+
+# Censorship score by jurisdiction
+def censor_score(series, minc, maxc, INTERVAL):
+ upscore = 0
+ downscore = 0
+ for i, v in enumerate(series):
+ if i > 0 and i - INTERVAL >= 0 and series[i] != None and series[i-INTERVAL] != None and series[i-INTERVAL] != 0 and minc[i]!= None and maxc[i]!= None:
+ in_minc = minc[i] * poisson.ppf(1-0.9999, series[i-INTERVAL])
+ in_maxc = maxc[i] * poisson.ppf(0.9999, series[i-INTERVAL])
+ downscore += 1 if minc[i] != None and v < in_minc else 0
+ upscore += 1 if maxc[i] != None and v > in_maxc else 0
+ return downscore, upscore
+
+def plot_target(tss, TARGET, xtitle, minx, maxx, DAYS=365, INTERV = 7):
+ ctarget = tss.get_country_series(TARGET)
+ c = n_day_rel(ctarget, INTERV)
+ absolute_plot(ctarget[-DAYS:], minx[-DAYS:], maxx[-DAYS:], tss.all_dates[-DAYS:],INTERV, xtitle = xtitle)
+
+
+## Make a league table of censorship + nice graphs
+def plot_all(tss, minx, maxx, INTERV, DAYS=None, rdir="img"):
+ rdir = os.path.realpath(rdir)
+ if not os.path.exists(rdir) or not os.path.isdir(rdir):
+ print "ERROR: %s does not exist or is not a directory." % rdir
+ return
+
+ summary_file = file(os.path.join(rdir, "summary.txt"), "w")
+
+ if DAYS == None:
+ DAYS = 6*31
+
+ s = tss.get_largest(200)
+ scores = []
+ for num, li in s:
+ print ".",
+ ds,us = censor_score(tss.get_country_series(li)[-DAYS:], minx[-DAYS:], maxx[-DAYS:], INTERV)
+ # print ds, us
+ scores += [(ds,num, us, li)]
+ scores.sort()
+ scores.reverse()
+ s = "\n=======================\n"
+ s+= "Report for %s to %s\n" % (tss.all_dates[-DAYS], tss.all_dates[-1])
+ s+= "=======================\n"
+ print s
+ summary_file.write(s)
+ for a,nx, b,c in scores:
+ if a > 0:
+ s = "%s -- down: %2d (up: %2d affected: %s)" % (c, a, b, nx)
+ print s
+ summary_file.write(s + "\n")
+ xtitle = (os.path.join(rdir, "%03d-%s-censor.png" % (a,c)), "Tor report for %s -- down: %2d (up: %2d affected: %s)" % (c, a, b, nx),"")
+ plot_target(tss, c,xtitle, minx, maxx, DAYS, INTERV)
+ summary_file.close()
+
+def main():
+ # Change these to customize script
+ CSV_FILE = "direct-users.csv"
+ GRAPH_DIR = "img"
+ INTERV = 7
+ DAYS= 6 * 31
+
+ tss = torstatstore(CSV_FILE)
+ l = tss.get_largest_locations(50)
+ minx, maxx = make_tendencies_minmax(l, INTERV)
+ plot_all(tss, minx, maxx, INTERV, DAYS, rdir=GRAPH_DIR)
+
+if __name__ == "__main__":
+ main()
1
0
r24433: {arm} Couple small fixes: fix: using Tor's internal address when n (arm/trunk/src/interface/connections)
by Damian Johnson 25 Mar '11
by Damian Johnson 25 Mar '11
25 Mar '11
Author: atagar
Date: 2011-03-25 02:30:48 +0000 (Fri, 25 Mar 2011)
New Revision: 24433
Modified:
arm/trunk/src/interface/connections/connEntry.py
Log:
Couple small fixes:
fix: using Tor's internal address when not expanding (patch by Fabian Keil)
fix: sorting scrubbed ip addresses at the end
Modified: arm/trunk/src/interface/connections/connEntry.py
===================================================================
--- arm/trunk/src/interface/connections/connEntry.py 2011-03-24 10:56:13 UTC (rev 24432)
+++ arm/trunk/src/interface/connections/connEntry.py 2011-03-25 02:30:48 UTC (rev 24433)
@@ -29,6 +29,9 @@
LABEL_FORMAT = "%s --> %s %s%s"
LABEL_MIN_PADDING = 2 # min space between listing label and following data
+# sort value for scrubbed ip addresses
+SCRUBBED_IP_VAL = 255 ** 4
+
CONFIG = {"features.connection.markInitialConnections": True,
"features.connection.showExitPort": True,
"features.connection.showColumn.fingerprint": True,
@@ -149,25 +152,28 @@
Provides the value of a single attribute used for sorting purposes.
"""
+ connLine = self.lines[0]
if attr == entries.SortAttr.IP_ADDRESS:
- return self.lines[0].sortIpAddr
+ if connLine.isPrivate(): return SCRUBBED_IP_VAL # orders at the end
+ return connLine.sortIpAddr
elif attr == entries.SortAttr.PORT:
- return self.lines[0].sortPort
+ return connLine.sortPort
elif attr == entries.SortAttr.HOSTNAME:
- return self.lines[0].foreign.getHostname("")
+ if connLine.isPrivate(): return ""
+ return connLine.foreign.getHostname("")
elif attr == entries.SortAttr.FINGERPRINT:
- return self.lines[0].foreign.getFingerprint()
+ return connLine.foreign.getFingerprint()
elif attr == entries.SortAttr.NICKNAME:
- myNickname = self.lines[0].foreign.getNickname()
+ myNickname = connLine.foreign.getNickname()
if myNickname == "UNKNOWN": return "z" * 20 # orders at the end
else: return myNickname.lower()
elif attr == entries.SortAttr.CATEGORY:
- return Category.indexOf(self.lines[0].getType())
+ return Category.indexOf(connLine.getType())
elif attr == entries.SortAttr.UPTIME:
- return self.lines[0].startTime
+ return connLine.startTime
elif attr == entries.SortAttr.COUNTRY:
if connections.isIpAddressPrivate(self.lines[0].foreign.getIpAddr()): return ""
- else: return self.lines[0].foreign.getLocale("")
+ else: return connLine.foreign.getLocale("")
else:
return entries.ConnectionPanelEntry.getSortValue(self, attr, listingType)
@@ -508,7 +514,8 @@
isExpansionType = not myType in (Category.PROGRAM, Category.CONTROL)
- srcAddress = myExternalIpAddr + localPort
+ if isExpansionType: srcAddress = myExternalIpAddr + localPort
+ else: srcAddress = self.local.getIpAddr() + localPort
src = "%-21s" % srcAddress # ip:port = max of 21 characters
dst = "%-26s" % dstAddress # ip:port (xx) = max of 26 characters
1
0
[metrics-tasks/master] Add code for bridge churn graph (#2794).
by karsten@torproject.org 24 Mar '11
by karsten@torproject.org 24 Mar '11
24 Mar '11
commit 8dde11c31d385d92d3dc41032438b62b693f6daf
Author: Karsten Loesing <karsten.loesing(a)gmx.net>
Date: Thu Mar 24 16:05:35 2011 +0100
Add code for bridge churn graph (#2794).
---
task-2794/.gitignore | 4 +
task-2794/README | 12 +++
task-2794/StillRunning.java | 139 +++++++++++++++++++++++++++++++++++++
task-2794/still-running-bridges.R | 15 ++++
4 files changed, 170 insertions(+), 0 deletions(-)
diff --git a/task-2794/.gitignore b/task-2794/.gitignore
new file mode 100644
index 0000000..939f812
--- /dev/null
+++ b/task-2794/.gitignore
@@ -0,0 +1,4 @@
+*.csv
+*.class
+*.png
+
diff --git a/task-2794/README b/task-2794/README
new file mode 100644
index 0000000..311c5b5
--- /dev/null
+++ b/task-2794/README
@@ -0,0 +1,12 @@
+Code to create a graph on "Uptimes of bridges that were running Jan 2,
+2011, 00:00:00 UTC":
+
+ - Generate assignments.csv and statuses.csv using the #2680 code and put
+ them in this directory.
+
+ - Compile and run the Java class:
+ $ javac StillRunning.java && java StillRunning
+
+ - Run the R code (note that this may take a few minutes!):
+ $ R --slave -f still-running-bridges.R
+
diff --git a/task-2794/StillRunning.java b/task-2794/StillRunning.java
new file mode 100644
index 0000000..111c085
--- /dev/null
+++ b/task-2794/StillRunning.java
@@ -0,0 +1,139 @@
+import java.io.*;
+import java.util.*;
+public class StillRunning {
+ public static void main(String[] args) throws Exception {
+
+ /* Parse bridge pool assignments. */
+ Map<String, String> assignments = new HashMap<String, String>();
+ BufferedReader br = new BufferedReader(new FileReader(
+ "assignments.csv"));
+ String line = br.readLine();
+ while ((line = br.readLine()) != null) {
+ String[] parts = line.split(",");
+ String fingerprint = parts[1];
+ String type = parts[2];
+ assignments.put(fingerprint, type);
+ }
+ br.close();
+
+ /* Parse running bridges in first status of the second day in the data
+ * set. */
+ br = new BufferedReader(new FileReader("statuses.csv"));
+ line = br.readLine();
+ if (!line.split(",")[15].equals("running")) {
+ System.out.println("Column 16 should be 'running'");
+ System.exit(1);
+ }
+ String dayOne = null, lastStatus = null;
+ List<String> fingerprints = new ArrayList<String>();
+ Map<String, String> addresses = new HashMap<String, String>();
+ while ((line = br.readLine()) != null) {
+ String[] parts = line.split(",");
+ String status = parts[0];
+ if (dayOne == null) {
+ dayOne = status.substring(0, "yyyy-mm-dd".length());
+ } else if (status.startsWith(dayOne)) {
+ continue;
+ }
+ String running = parts[15];
+ if (!running.equals("TRUE")) {
+ continue;
+ }
+ if (lastStatus != null && !status.equals(lastStatus)) {
+ break;
+ }
+ lastStatus = status;
+ String fingerprint = parts[1];
+ fingerprints.add(fingerprint);
+ String address = parts[4];
+ addresses.put(fingerprint, address);
+ }
+
+ /* Parse subsequent statuses and count how often these bridges
+ * occur. */
+ Map<String, Integer>
+ fingerprintAnyCount = new HashMap<String, Integer>(),
+ fingerprintSameCount = new HashMap<String, Integer>();
+ for (String fingerprint : fingerprints) {
+ fingerprintAnyCount.put(fingerprint, 1);
+ fingerprintSameCount.put(fingerprint, 1);
+ }
+ do {
+ String[] parts = line.split(",");
+ String status = parts[0];
+ String running = parts[15];
+ if (!running.equals("TRUE")) {
+ continue;
+ }
+ String fingerprint = parts[1];
+ if (!fingerprints.contains(fingerprint)) {
+ continue;
+ }
+ fingerprintAnyCount.put(fingerprint,
+ fingerprintAnyCount.get(fingerprint) + 1);
+ String address = parts[4];
+ if (addresses.get(fingerprint).equals(address)) {
+ fingerprintSameCount.put(fingerprint,
+ fingerprintSameCount.get(fingerprint) + 1);
+ }
+ } while ((line = br.readLine()) != null);
+
+ /* Create two lists of fingerprints, ordered by the number of
+ * occurrences. */
+ SortedMap<String, String>
+ sortAnyFingerprints = new TreeMap<String, String>(),
+ sortSameFingerprints = new TreeMap<String, String>();
+ for (Map.Entry<String, Integer> e : fingerprintAnyCount.entrySet()) {
+ sortAnyFingerprints.put(String.format("%05d %s", e.getValue(),
+ e.getKey()), e.getKey());
+ }
+ List<String> sortedAnyFingerprints = new ArrayList<String>(
+ sortAnyFingerprints.values());
+ for (Map.Entry<String, Integer> e : fingerprintSameCount.entrySet()) {
+ sortSameFingerprints.put(String.format("%05d %s", e.getValue(),
+ e.getKey()), e.getKey());
+ }
+ List<String> sortedSameFingerprints = new ArrayList<String>(
+ sortSameFingerprints.values());
+
+ /* Write bridges of first status to disk. */
+ BufferedWriter bw = new BufferedWriter(new FileWriter(
+ "still-running-bridges.csv"));
+ bw.write("status,anyid,sameid,type,addresschange\n");
+ for (String fingerprint : sortedAnyFingerprints) {
+ bw.write(lastStatus + ","
+ + sortedAnyFingerprints.indexOf(fingerprint) + ","
+ + sortedSameFingerprints.indexOf(fingerprint) + ","
+ + assignments.get(fingerprint) + ",FALSE\n");
+ }
+
+ /* Parse statuses once again and write bridges to disk. */
+ br = new BufferedReader(new FileReader("statuses.csv"));
+ line = br.readLine();
+ while ((line = br.readLine()) != null) {
+ String[] parts = line.split(",");
+ String status = parts[0];
+ if (status.startsWith(dayOne)) {
+ continue;
+ }
+ String running = parts[15];
+ if (!running.equals("TRUE")) {
+ continue;
+ }
+ String fingerprint = parts[1];
+ if (!fingerprints.contains(fingerprint)) {
+ continue;
+ }
+ String address = parts[4];
+ boolean addressChange = !addresses.get(fingerprint).equals(address);
+ bw.write(status + ","
+ + sortedAnyFingerprints.indexOf(fingerprint) + ","
+ + sortedSameFingerprints.indexOf(fingerprint) + ","
+ + assignments.get(fingerprint) + ","
+ + (addressChange ? "TRUE" : "FALSE") + "\n");
+ }
+ bw.close();
+ br.close();
+ }
+}
+
diff --git a/task-2794/still-running-bridges.R b/task-2794/still-running-bridges.R
new file mode 100644
index 0000000..8752b07
--- /dev/null
+++ b/task-2794/still-running-bridges.R
@@ -0,0 +1,15 @@
+library(ggplot2)
+anyip <- read.csv("still-running-bridges.csv", stringsAsFactors = FALSE)
+sameip <- anyip[anyip$addresschange == FALSE, ]
+data <- rbind(
+ data.frame(status = anyip$status, bridgeid = anyip$anyid, address = "any IP address"),
+ data.frame(status = sameip$status, bridgeid = sameip$sameid, address = "same IP address"))
+ggplot(data, aes(x = as.POSIXct(status),
+ y = (max(data$bridgeid) - bridgeid) / max(data$bridgeid))) +
+facet_grid(address ~ .) +
+geom_point(size = 0.2, colour = "springgreen3") +
+scale_x_datetime(name = "") +
+scale_y_continuous(name = "", formatter = "percent") +
+opts(title = "Uptimes of bridges that were running Jan 2, 2011, 00:00:00 UTC\n")
+ggsave(filename = "still-running-bridges.png", width = 8, height = 5, dpi = 72)
+
1
0
commit 9cd39bbc7dd073af5b86485bf0a074ff01e9b4c8
Author: Erinn Clark <erinn(a)torproject.org>
Date: Thu Mar 24 12:29:41 2011 +0100
add firefox 3.6 patch
---
.../non-blocking-socks-firefox-3.6.patch | 1637 ++++++++++++++++++++
1 files changed, 1637 insertions(+), 0 deletions(-)
diff --git a/src/current-patches/non-blocking-socks-firefox-3.6.patch b/src/current-patches/non-blocking-socks-firefox-3.6.patch
new file mode 100644
index 0000000..fd24905
--- /dev/null
+++ b/src/current-patches/non-blocking-socks-firefox-3.6.patch
@@ -0,0 +1,1637 @@
+--- a/netwerk/base/src/nsSocketTransport2.cpp
++++ a/netwerk/base/src/nsSocketTransport2.cpp
+@@ -1222,16 +1222,26 @@ nsSocketTransport::InitiateSocket()
+ // connection... wouldn't we need to call ProxyStartSSL after a call
+ // to PR_ConnectContinue indicates that we are connected?
+ //
+ // XXX this appears to be what the old socket transport did. why
+ // isn't this broken?
+ }
+ }
+ //
++ // A SOCKS request was rejected; get the actual error code from
++ // the OS error
++ //
++ else if (PR_UNKNOWN_ERROR == code &&
++ mProxyTransparent &&
++ !mProxyHost.IsEmpty()) {
++ code = PR_GetOSError();
++ rv = ErrorAccordingToNSPR(code);
++ }
++ //
+ // The connection was refused...
+ //
+ else {
+ rv = ErrorAccordingToNSPR(code);
+ if ((rv == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
+ rv = NS_ERROR_PROXY_CONNECTION_REFUSED;
+ }
+ }
+@@ -1544,17 +1554,26 @@ nsSocketTransport::OnSocketReady(PRFileD
+ //
+ // If the connect is still not ready, then continue polling...
+ //
+ if ((PR_WOULD_BLOCK_ERROR == code) || (PR_IN_PROGRESS_ERROR == code)) {
+ // Set up the select flags for connect...
+ mPollFlags = (PR_POLL_EXCEPT | PR_POLL_WRITE);
+ // Update poll timeout in case it was changed
+ mPollTimeout = mTimeouts[TIMEOUT_CONNECT];
+- }
++ }
++ //
++ // The SOCKS proxy rejected our request. Find out why.
++ //
++ else if (PR_UNKNOWN_ERROR == code &&
++ mProxyTransparent &&
++ !mProxyHost.IsEmpty()) {
++ code = PR_GetOSError();
++ mCondition = ErrorAccordingToNSPR(code);
++ }
+ else {
+ //
+ // else, the connection failed...
+ //
+ mCondition = ErrorAccordingToNSPR(code);
+ if ((mCondition == NS_ERROR_CONNECTION_REFUSED) && !mProxyHost.IsEmpty())
+ mCondition = NS_ERROR_PROXY_CONNECTION_REFUSED;
+ SOCKET_LOG((" connection failed! [reason=%x]\n", mCondition));
+--- a/netwerk/socket/base/nsSOCKSIOLayer.cpp
++++ a/netwerk/socket/base/nsSOCKSIOLayer.cpp
+@@ -20,16 +20,17 @@
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Justin Bradford <jab(a)atdot.org>
+ * Bradley Baetz <bbaetz(a)acm.org>
+ * Darin Fisher <darin(a)meer.net>
+ * Malcolm Smith <malsmith(a)cs.rmit.edu.au>
++ * Christopher Davis <chrisd(a)torproject.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+@@ -63,51 +64,115 @@ static PRLogModuleInfo *gSOCKSLog;
+
+ #else
+ #define LOGDEBUG(args)
+ #define LOGERROR(args)
+ #endif
+
+ class nsSOCKSSocketInfo : public nsISOCKSSocketInfo
+ {
++ enum State {
++ SOCKS_INITIAL,
++ SOCKS_CONNECTING_TO_PROXY,
++ SOCKS4_WRITE_CONNECT_REQUEST,
++ SOCKS4_READ_CONNECT_RESPONSE,
++ SOCKS5_WRITE_AUTH_REQUEST,
++ SOCKS5_READ_AUTH_RESPONSE,
++ SOCKS5_WRITE_CONNECT_REQUEST,
++ SOCKS5_READ_CONNECT_RESPONSE_TOP,
++ SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ SOCKS_CONNECTED,
++ SOCKS_FAILED
++ };
++
++ // A buffer of 262 bytes should be enough for any request and response
++ // in case of SOCKS4 as well as SOCKS5
++ static const PRUint32 BUFFER_SIZE = 262;
++ static const PRUint32 MAX_HOSTNAME_LEN = 255;
++
+ public:
+ nsSOCKSSocketInfo();
+- virtual ~nsSOCKSSocketInfo() {}
++ virtual ~nsSOCKSSocketInfo() { HandshakeFinished(); }
+
+ NS_DECL_ISUPPORTS
+ NS_DECL_NSISOCKSSOCKETINFO
+
+ void Init(PRInt32 version,
+ const char *proxyHost,
+ PRInt32 proxyPort,
+ const char *destinationHost,
+ PRUint32 flags);
+
+- const nsCString &DestinationHost() { return mDestinationHost; }
+- const nsCString &ProxyHost() { return mProxyHost; }
+- PRInt32 ProxyPort() { return mProxyPort; }
+- PRInt32 Version() { return mVersion; }
+- PRUint32 Flags() { return mFlags; }
++ void SetConnectTimeout(PRIntervalTime to);
++ PRStatus DoHandshake(PRFileDesc *fd, PRInt16 oflags = -1);
++ PRInt16 GetPollFlags() const;
++ bool IsConnected() const { return mState == SOCKS_CONNECTED; }
+
+ private:
++ void HandshakeFinished(PRErrorCode err = 0);
++ PRStatus ConnectToProxy(PRFileDesc *fd);
++ PRStatus ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags);
++ PRStatus WriteV4ConnectRequest();
++ PRStatus ReadV4ConnectResponse();
++ PRStatus WriteV5AuthRequest();
++ PRStatus ReadV5AuthResponse();
++ PRStatus WriteV5ConnectRequest();
++ PRStatus ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len);
++ PRStatus ReadV5ConnectResponseTop();
++ PRStatus ReadV5ConnectResponseBottom();
++
++ void WriteUint8(PRUint8 d);
++ void WriteUint16(PRUint16 d);
++ void WriteUint32(PRUint32 d);
++ void WriteNetAddr(const PRNetAddr *addr);
++ void WriteNetPort(const PRNetAddr *addr);
++ void WriteString(const nsACString &str);
++
++ PRUint8 ReadUint8();
++ PRUint16 ReadUint16();
++ PRUint32 ReadUint32();
++ void ReadNetAddr(PRNetAddr *addr, PRUint16 fam);
++ void ReadNetPort(PRNetAddr *addr);
++
++ void WantRead(PRUint32 sz);
++ PRStatus ReadFromSocket(PRFileDesc *fd);
++ PRStatus WriteToSocket(PRFileDesc *fd);
++
++private:
++ State mState;
++ PRUint8 * mData;
++ PRUint8 * mDataIoPtr;
++ PRUint32 mDataLength;
++ PRUint32 mReadOffset;
++ PRUint32 mAmountToRead;
++ nsCOMPtr<nsIDNSRecord> mDnsRec;
++
+ nsCString mDestinationHost;
+ nsCString mProxyHost;
+ PRInt32 mProxyPort;
+ PRInt32 mVersion; // SOCKS version 4 or 5
+ PRUint32 mFlags;
+ PRNetAddr mInternalProxyAddr;
+ PRNetAddr mExternalProxyAddr;
+ PRNetAddr mDestinationAddr;
++ PRIntervalTime mTimeout;
+ };
+
+ nsSOCKSSocketInfo::nsSOCKSSocketInfo()
+- : mProxyPort(-1)
++ : mState(SOCKS_INITIAL)
++ , mDataIoPtr(nsnull)
++ , mDataLength(0)
++ , mReadOffset(0)
++ , mAmountToRead(0)
++ , mProxyPort(-1)
+ , mVersion(-1)
+ , mFlags(0)
++ , mTimeout(PR_INTERVAL_NO_TIMEOUT)
+ {
++ mData = new PRUint8[BUFFER_SIZE];
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mInternalProxyAddr);
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mExternalProxyAddr);
+ PR_InitializeNetAddr(PR_IpAddrAny, 0, &mDestinationAddr);
+ }
+
+ void
+ nsSOCKSSocketInfo::Init(PRInt32 version, const char *proxyHost, PRInt32 proxyPort, const char *host, PRUint32 flags)
+ {
+@@ -157,647 +222,817 @@ nsSOCKSSocketInfo::GetInternalProxyAddr(
+
+ NS_IMETHODIMP
+ nsSOCKSSocketInfo::SetInternalProxyAddr(PRNetAddr *aInternalProxyAddr)
+ {
+ memcpy(&mInternalProxyAddr, aInternalProxyAddr, sizeof(PRNetAddr));
+ return NS_OK;
+ }
+
+-static PRInt32
+-pr_RecvAll(PRFileDesc *fd, unsigned char *buf, PRInt32 amount, PRIntn flags,
+- PRIntervalTime *timeout)
++// There needs to be a means of distinguishing between connection errors
++// that the SOCKS server reports when it rejects a connection request, and
++// connection errors that happen while attempting to connect to the SOCKS
++// server. Otherwise, Firefox will report incorrectly that the proxy server
++// is refusing connections when a SOCKS request is rejected by the proxy.
++// When a SOCKS handshake failure occurs, the PR error is set to
++// PR_UNKNOWN_ERROR, and the real error code is returned via the OS error.
++void
++nsSOCKSSocketInfo::HandshakeFinished(PRErrorCode err)
+ {
+- PRInt32 bytesRead = 0;
+- PRInt32 offset = 0;
++ if (err == 0) {
++ mState = SOCKS_CONNECTED;
++ } else {
++ mState = SOCKS_FAILED;
++ PR_SetError(PR_UNKNOWN_ERROR, err);
++ }
+
+- while (offset < amount) {
+- PRIntervalTime start_time = PR_IntervalNow();
+- bytesRead = PR_Recv(fd, buf + offset, amount - offset, flags, *timeout);
+- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
+-
+- if (elapsed > *timeout) {
+- *timeout = 0;
+- } else {
+- *timeout -= elapsed;
+- }
+-
+- if (bytesRead > 0) {
+- offset += bytesRead;
+- } else if (bytesRead == 0 || offset != 0) {
+- return offset;
+- } else {
+- return bytesRead;
+- }
+-
+- if (*timeout == 0) {
+- LOGERROR(("PR_Recv() timed out. amount = %d. offset = %d.",
+- amount, offset));
+- return offset;
+- }
+- }
+- return offset;
++ // We don't need the buffer any longer, so free it.
++ delete [] mData;
++ mData = nsnull;
++ mDataIoPtr = nsnull;
++ mDataLength = 0;
++ mReadOffset = 0;
++ mAmountToRead = 0;
+ }
+
+-static PRInt32
+-pr_Send(PRFileDesc *fd, const void *buf, PRInt32 amount, PRIntn flags,
+- PRIntervalTime *timeout)
++PRStatus
++nsSOCKSSocketInfo::ConnectToProxy(PRFileDesc *fd)
+ {
+- PRIntervalTime start_time = PR_IntervalNow();
+- PRInt32 retval = PR_Send(fd, buf, amount, flags, *timeout);
+- PRIntervalTime elapsed = PR_IntervalNow() - start_time;
++ PRStatus status;
++ nsresult rv;
+
+- if (elapsed > *timeout) {
+- *timeout = 0;
+- LOGERROR(("PR_Send() timed out. amount = %d. retval = %d.",
+- amount, retval));
+- return retval;
+- } else {
+- *timeout -= elapsed;
+- }
++ NS_ABORT_IF_FALSE(mState == SOCKS_INITIAL,
++ "Must be in initial state to make connection!");
+
+- if (retval <= 0) {
+- LOGERROR(("PR_Send() failed. amount = %d. retval = %d.",
+- amount, retval));
+- }
++ // If we haven't performed the DNS lookup, do that now.
++ if (!mDnsRec) {
++ nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
++ if (!dns)
++ return PR_FAILURE;
+
+- return retval;
+-}
+-
+-// Negotiate a SOCKS 5 connection. Assumes the TCP connection to the socks
+-// server port has been established.
+-static nsresult
+-ConnectSOCKS5(PRFileDesc *fd, const PRNetAddr *addr, PRNetAddr *extAddr, PRIntervalTime timeout)
+-{
+- int request_len = 0;
+- int response_len = 0;
+- int desired_len = 0;
+- unsigned char request[22];
+- unsigned char response[262];
+-
+- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(extAddr, NS_ERROR_NOT_INITIALIZED);
+-
+- request[0] = 0x05; // SOCKS version 5
+- request[1] = 0x01; // number of auth procotols we recognize
+- // auth protocols
+- request[2] = 0x00; // no authentication required
+- // compliant implementations MUST implement GSSAPI
+- // and SHOULD implement username/password and MAY
+- // implement CHAP
+- // TODO: we don't implement these
+- //request[3] = 0x01; // GSSAPI
+- //request[4] = 0x02; // username/password
+- //request[5] = 0x03; // CHAP
+-
+- request_len = 2 + request[1];
+- int write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
+- }
+-
+- // get the server's response.
+- desired_len = 2;
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
+-
+- if (response_len < desired_len) {
+- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
+-
+- if (response[0] != 0x05) {
+- // it's a either not SOCKS or not our version
+- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
+- return NS_ERROR_FAILURE;
+- }
+- switch (response[1]) {
+- case 0x00:
+- // no auth
+- break;
+- case 0x01:
+- // GSSAPI
+- // TODO: implement
+- LOGERROR(("Server want to use GSSAPI to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- case 0x02:
+- // username/password
+- // TODO: implement
+- LOGERROR(("Server want to use username/password to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- case 0x03:
+- // CHAP
+- // TODO: implement?
+- LOGERROR(("Server want to use CHAP to authenticate, but we don't support it."));
+- return NS_ERROR_FAILURE;
+- default:
+- // unrecognized auth method
+- LOGERROR(("Uncrecognized authentication method received: %x", response[1]));
+- return NS_ERROR_FAILURE;
+- }
+-
+- // we are now authenticated, so lets tell
+- // the server where to connect to
+-
+- request_len = 0;
+-
+- request[0] = 0x05; // SOCKS version 5
+- request[1] = 0x01; // CONNECT command
+- request[2] = 0x00; // obligatory reserved field (perfect for MS tampering!)
+-
+- // get destination port
+- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
+- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
+-
+- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
+-
+- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
+-
+- // if the PROXY_RESOLVES_HOST flag is set, we assume
+- // that the transport wants us to pass the SOCKS server the
+- // hostname and port and let it do the name resolution.
+-
+- // the real destination hostname and port was stored
+- // in our info object earlier when this layer was created.
+-
+- const nsCString& destHost = info->DestinationHost();
+-
+- LOGDEBUG(("host:port -> %s:%li", destHost.get(), destPort));
+-
+- request[3] = 0x03; // encoding of destination address (3 == hostname)
+-
+- int host_len = destHost.Length();
+- if (host_len > 255) {
+- // SOCKS5 transmits the length of the hostname in a single char.
+- // This gives us an absolute limit of 255 chars in a hostname, and
+- // there's nothing we can do to extend it. I don't think many
+- // hostnames will ever be bigger than this, so hopefully it's an
+- // uneventful abort condition.
+- LOGERROR (("Hostname too big for SOCKS5."));
+- return NS_ERROR_INVALID_ARG;
+- }
+- request[4] = (char) host_len;
+- request_len = 5;
+-
+- // Send the initial header first...
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
+- }
+-
+- // Now send the hostname...
+- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
+- if (write_len != host_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
+- }
+-
+- // There's no data left because we just sent it.
+- request_len = 0;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
+-
+- request[3] = 0x01; // encoding of destination address (1 == IPv4)
+- request_len = 8; // 4 for address, 4 SOCKS headers
+-
+- char * ip = (char*)(&addr->inet.ip);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
+-
+- request[3] = 0x04; // encoding of destination address (4 == IPv6)
+- request_len = 20; // 16 for address, 4 SOCKS headers
+-
+- char * ip = (char*)(&addr->ipv6.ip.pr_s6_addr);
+- request[4] = *ip++; request[5] = *ip++;
+- request[6] = *ip++; request[7] = *ip++;
+- request[8] = *ip++; request[9] = *ip++;
+- request[10] = *ip++; request[11] = *ip++;
+- request[12] = *ip++; request[13] = *ip++;
+- request[14] = *ip++; request[15] = *ip++;
+- request[16] = *ip++; request[17] = *ip++;
+- request[18] = *ip++; request[19] = *ip++;
+-
+- // we're going to test to see if this address can
+- // be mapped back into IPv4 without loss. if so,
+- // we'll use IPv4 instead, as reliable SOCKS server
+- // support for IPv6 is probably questionable.
+-
+- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
+- request[3] = 0x01; // ipv4 encoding
+- request[4] = request[16];
+- request[5] = request[17];
+- request[6] = request[18];
+- request[7] = request[19];
+- request_len -= 12;
+- }
+- } else {
+- // Unknown address type
+- LOGERROR(("Don't know what kind of IP address this is."));
+- return NS_ERROR_FAILURE;
+- }
+-
+- // add the destination port to the request
+- request[request_len] = (unsigned char)(destPort >> 8);
+- request[request_len+1] = (unsigned char)destPort;
+- request_len += 2;
+-
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- // bad write
+- return NS_ERROR_FAILURE;
+- }
+-
+- desired_len = 5;
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
+- if (response_len < desired_len) { // bad read
+- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
+-
+- if (response[0] != 0x05) {
+- // bad response
+- LOGERROR(("Not a SOCKS 5 reply. Expected: 5; received: %x", response[0]));
+- return NS_ERROR_FAILURE;
+- }
+-
+- switch(response[1]) {
+- case 0x00: break; // success
+- case 0x01: LOGERROR(("SOCKS 5 server rejected connect request: 01, General SOCKS server failure."));
+- return NS_ERROR_FAILURE;
+- case 0x02: LOGERROR(("SOCKS 5 server rejected connect request: 02, Connection not allowed by ruleset."));
+- return NS_ERROR_FAILURE;
+- case 0x03: LOGERROR(("SOCKS 5 server rejected connect request: 03, Network unreachable."));
+- return NS_ERROR_FAILURE;
+- case 0x04: LOGERROR(("SOCKS 5 server rejected connect request: 04, Host unreachable."));
+- return NS_ERROR_FAILURE;
+- case 0x05: LOGERROR(("SOCKS 5 server rejected connect request: 05, Connection refused."));
+- return NS_ERROR_FAILURE;
+- case 0x06: LOGERROR(("SOCKS 5 server rejected connect request: 06, TTL expired."));
+- return NS_ERROR_FAILURE;
+- case 0x07: LOGERROR(("SOCKS 5 server rejected connect request: 07, Command not supported."));
+- return NS_ERROR_FAILURE;
+- case 0x08: LOGERROR(("SOCKS 5 server rejected connect request: 08, Address type not supported."));
+- return NS_ERROR_FAILURE;
+- default: LOGERROR(("SOCKS 5 server rejected connect request: %x.", response[1]));
+- return NS_ERROR_FAILURE;
+-
+-
+- }
+-
+- switch (response[3]) {
+- case 0x01: // IPv4
+- desired_len = 4 + 2 - 1;
+- break;
+- case 0x03: // FQDN
+- desired_len = response[4] + 2;
+- break;
+- case 0x04: // IPv6
+- desired_len = 16 + 2 - 1;
+- break;
+- default: // unknown format
+- return NS_ERROR_FAILURE;
+- break;
+- }
+- response_len = pr_RecvAll(fd, response + 5, desired_len, 0, &timeout);
+- if (response_len < desired_len) { // bad read
+- LOGERROR(("pr_RecvAll() failed getting connect command reply. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
+- }
+- response_len += 5;
+-
+- // get external bound address (this is what
+- // the outside world sees as "us")
+- char *ip = nsnull;
+- PRUint16 extPort = 0;
+-
+- switch (response[3]) {
+- case 0x01: // IPv4
+-
+- extPort = (response[8] << 8) | response[9];
+-
+- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET, extPort, extAddr);
+-
+- ip = (char*)(&extAddr->inet.ip);
+- *ip++ = response[4];
+- *ip++ = response[5];
+- *ip++ = response[6];
+- *ip++ = response[7];
+-
+- break;
+- case 0x04: // IPv6
+-
+- extPort = (response[20] << 8) | response[21];
+-
+- PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, extPort, extAddr);
+-
+- ip = (char*)(&extAddr->ipv6.ip.pr_s6_addr);
+- *ip++ = response[4]; *ip++ = response[5];
+- *ip++ = response[6]; *ip++ = response[7];
+- *ip++ = response[8]; *ip++ = response[9];
+- *ip++ = response[10]; *ip++ = response[11];
+- *ip++ = response[12]; *ip++ = response[13];
+- *ip++ = response[14]; *ip++ = response[15];
+- *ip++ = response[16]; *ip++ = response[17];
+- *ip++ = response[18]; *ip++ = response[19];
+-
+- break;
+- case 0x03: // FQDN
+- // if we get here, we don't know our external address.
+- // however, as that's possibly not critical to the user,
+- // we let it slide.
+- extPort = (response[response_len - 2] << 8) |
+- response[response_len - 1];
+- PR_InitializeNetAddr(PR_IpAddrNull, extPort, extAddr);
+- break;
+- }
+- return NS_OK;
+-}
+-
+-// Negotiate a SOCKS 4 connection. Assumes the TCP connection to the socks
+-// server port has been established.
+-static nsresult
+-ConnectSOCKS4(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime timeout)
+-{
+- int request_len = 0;
+- int write_len;
+- int response_len = 0;
+- int desired_len = 0;
+- char *ip = nsnull;
+- unsigned char request[12];
+- unsigned char response[10];
+-
+- NS_ENSURE_TRUE(fd, NS_ERROR_NOT_INITIALIZED);
+- NS_ENSURE_TRUE(addr, NS_ERROR_NOT_INITIALIZED);
+-
+- request[0] = 0x04; // SOCKS version 4
+- request[1] = 0x01; // CD command code -- 1 for connect
+-
+- // destination port
+- PRInt32 destPort = PR_ntohs(PR_NetAddrInetPort(addr));
+-
+- // store the port
+- request[2] = (unsigned char)(destPort >> 8);
+- request[3] = (unsigned char)destPort;
+-
+- // username
+- request[8] = 'M';
+- request[9] = 'O';
+- request[10] = 'Z';
+-
+- request[11] = 0x00;
+-
+- request_len = 12;
+-
+- nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
+-
+- if (info->Flags() & nsISocketProvider::PROXY_RESOLVES_HOST) {
+-
+- LOGDEBUG(("using server to resolve hostnames rather than resolving it first\n"));
+-
+- // if the PROXY_RESOLVES_HOST flag is set, we assume that the
+- // transport wants us to pass the SOCKS server the hostname
+- // and port and let it do the name resolution.
+-
+- // an extension to SOCKS 4, called 4a, specifies a way
+- // to do this, so we'll try that and hope the
+- // server supports it.
+-
+- // the real destination hostname and port was stored
+- // in our info object earlier when this layer was created.
+-
+- const nsCString& destHost = info->DestinationHost();
+-
+- LOGDEBUG(("host:port -> %s:%li\n", destHost.get(), destPort));
+-
+- // the IP portion of the query is set to this special address.
+- request[4] = 0;
+- request[5] = 0;
+- request[6] = 0;
+- request[7] = 1;
+-
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
+- }
+-
+- // Remember the NULL.
+- int host_len = destHost.Length() + 1;
+-
+- write_len = pr_Send(fd, destHost.get(), host_len, 0, &timeout);
+- if (write_len != host_len) {
+- return NS_ERROR_FAILURE;
+- }
+-
+- // No data to send, just sent it.
+- request_len = 0;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET) { // IPv4
+-
+- // store the ip
+- ip = (char*)(&addr->inet.ip);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
+-
+- } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) { // IPv6
+-
+- // IPv4 address encoded in an IPv6 address
+- if (PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
+- // store the ip
+- ip = (char*)(&addr->ipv6.ip.pr_s6_addr[12]);
+- request[4] = *ip++;
+- request[5] = *ip++;
+- request[6] = *ip++;
+- request[7] = *ip++;
+- } else {
+- LOGERROR(("IPv6 is not supported in SOCKS 4."));
+- return NS_ERROR_FAILURE; // SOCKS 4 can't do IPv6
+- }
+-
+- } else {
+- LOGERROR(("Don't know what kind of IP address this is."));
+- return NS_ERROR_FAILURE; // don't recognize this type
+- }
+-
+- if (request_len > 0) {
+- write_len = pr_Send(fd, request, request_len, 0, &timeout);
+- if (write_len != request_len) {
+- return NS_ERROR_FAILURE;
++ rv = dns->Resolve(mProxyHost, 0, getter_AddRefs(mDnsRec));
++ if (NS_FAILED(rv)) {
++ LOGERROR(("socks: DNS lookup for SOCKS proxy %s failed",
++ mProxyHost.get()));
++ return PR_FAILURE;
+ }
+ }
+
+- // get the server's response
+- desired_len = 8; // size of the response
+- response_len = pr_RecvAll(fd, response, desired_len, 0, &timeout);
+- if (response_len < desired_len) {
+- LOGERROR(("pr_RecvAll() failed. response_len = %d.", response_len));
+- return NS_ERROR_FAILURE;
++ do {
++ rv = mDnsRec->GetNextAddr(mProxyPort, &mInternalProxyAddr);
++ // No more addresses to try? If so, we'll need to bail
++ if (NS_FAILED(rv)) {
++ LOGERROR(("socks: unable to connect to SOCKS proxy, %s",
++ mProxyHost.get()));
++ return PR_FAILURE;
++ }
++
++#if defined(PR_LOGGING)
++ char buf[64];
++ PR_NetAddrToString(&mInternalProxyAddr, buf, sizeof(buf));
++ LOGDEBUG(("socks: trying proxy server, %s:%hu",
++ buf, PR_ntohs(PR_NetAddrInetPort(&mInternalProxyAddr))));
++#endif
++ status = fd->lower->methods->connect(fd->lower,
++ &mInternalProxyAddr, mTimeout);
++ if (status != PR_SUCCESS) {
++ PRErrorCode c = PR_GetError();
++ // If EINPROGRESS, return now and check back later after polling
++ if (c == PR_WOULD_BLOCK_ERROR || c == PR_IN_PROGRESS_ERROR) {
++ mState = SOCKS_CONNECTING_TO_PROXY;
++ return status;
++ }
++ }
++ } while (status != PR_SUCCESS);
++
++ // Connected now, start SOCKS
++ if (mVersion == 4)
++ return WriteV4ConnectRequest();
++ return WriteV5AuthRequest();
++}
++
++PRStatus
++nsSOCKSSocketInfo::ContinueConnectingToProxy(PRFileDesc *fd, PRInt16 oflags)
++{
++ PRStatus status;
++
++ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
++ "Continuing connection in wrong state!");
++
++ LOGDEBUG(("socks: continuing connection to proxy"));
++
++ status = fd->lower->methods->connectcontinue(fd->lower, oflags);
++ if (status != PR_SUCCESS) {
++ PRErrorCode c = PR_GetError();
++ if (c != PR_WOULD_BLOCK_ERROR && c != PR_IN_PROGRESS_ERROR) {
++ // A connection failure occured, try another address
++ mState = SOCKS_INITIAL;
++ return ConnectToProxy(fd);
++ }
++
++ // We're still connecting
++ return PR_FAILURE;
+ }
+
+- if ((response[0] != 0x00) && (response[0] != 0x04)) {
+- // Novell BorderManager sends a response of type 4, should be zero
+- // According to the spec. Cope with this brokenness.
+- // it's not a SOCKS 4 reply or version 0 of the reply code
+- LOGERROR(("Not a SOCKS 4 reply. Expected: 0; received: %x.", response[0]));
+- return NS_ERROR_FAILURE;
++ // Connected now, start SOCKS
++ if (mVersion == 4)
++ return WriteV4ConnectRequest();
++ return WriteV5AuthRequest();
++}
++
++PRStatus
++nsSOCKSSocketInfo::WriteV4ConnectRequest()
++{
++ PRNetAddr *addr = &mDestinationAddr;
++ PRInt32 proxy_resolve;
++
++ NS_ABORT_IF_FALSE(mState == SOCKS_CONNECTING_TO_PROXY,
++ "Invalid state!");
++
++ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
++
++ mDataLength = 0;
++ mState = SOCKS4_WRITE_CONNECT_REQUEST;
++
++ LOGDEBUG(("socks4: sending connection request (socks4a resolve? %s)",
++ proxy_resolve? "yes" : "no"));
++
++ // Send a SOCKS 4 connect request.
++ WriteUint8(0x04); // version -- 4
++ WriteUint8(0x01); // command -- connect
++ WriteNetPort(addr);
++ if (proxy_resolve) {
++ // Add the full name, null-terminated, to the request
++ // according to SOCKS 4a. A fake IP address, with the first
++ // four bytes set to 0 and the last byte set to something other
++ // than 0, is used to notify the proxy that this is a SOCKS 4a
++ // request. This request type works for Tor and perhaps others.
++ WriteUint32(PR_htonl(0x00000001)); // Fake IP
++ WriteUint8(0x00); // Send an emtpy username
++ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
++ LOGERROR(("socks4: destination host name is too long!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++ WriteString(mDestinationHost); // Hostname
++ WriteUint8(0x00);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ WriteNetAddr(addr); // Add the IPv4 address
++ WriteUint8(0x00); // Send an emtpy username
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ LOGERROR(("socks: SOCKS 4 can't handle IPv6 addresses!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
+ }
+
+- if (response[1] != 0x5A) { // = 90: request granted
+- // connect request not granted
+- LOGERROR(("Connection request refused. Expected: 90; received: %d.", response[1]));
+- return NS_ERROR_FAILURE;
+- }
+-
+- return NS_OK;
+-
++ return PR_SUCCESS;
+ }
+
++PRStatus
++nsSOCKSSocketInfo::ReadV4ConnectResponse()
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS4_READ_CONNECT_RESPONSE,
++ "Handling SOCKS 4 connection reply in wrong state!");
++ NS_ABORT_IF_FALSE(mDataLength == 8,
++ "SOCKS 4 connection reply must be 8 bytes!");
++
++ LOGDEBUG(("socks4: checking connection reply"));
++
++ if (ReadUint8() != 0x00) {
++ LOGERROR(("socks4: wrong connection reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
++
++ // See if our connection request was granted
++ if (ReadUint8() == 90) {
++ LOGDEBUG(("socks4: connection successful!"));
++ HandshakeFinished();
++ return PR_SUCCESS;
++ }
++
++ LOGERROR(("socks4: unable to connect"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++}
++
++PRStatus
++nsSOCKSSocketInfo::WriteV5AuthRequest()
++{
++ NS_ABORT_IF_FALSE(mVersion == 5, "SOCKS version must be 5!");
++
++ mState = SOCKS5_WRITE_AUTH_REQUEST;
++
++ // Send an initial SOCKS 5 greeting
++ LOGDEBUG(("socks5: sending auth methods"));
++ WriteUint8(0x05); // version -- 5
++ WriteUint8(0x01); // # auth methods -- 1
++ WriteUint8(0x00); // we don't support authentication
++
++ return PR_SUCCESS;
++}
++
++PRStatus
++nsSOCKSSocketInfo::ReadV5AuthResponse()
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_AUTH_RESPONSE,
++ "Handling SOCKS 5 auth method reply in wrong state!");
++ NS_ABORT_IF_FALSE(mDataLength == 2,
++ "SOCKS 5 auth method reply must be 2 bytes!");
++
++ LOGDEBUG(("socks5: checking auth method reply"));
++
++ // Check version number
++ if (ReadUint8() != 0x05) {
++ LOGERROR(("socks5: unexpected version in the reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
++
++ // Make sure our authentication choice was accepted
++ if (ReadUint8() != 0x00) {
++ LOGERROR(("socks5: server did not accept our authentication method"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
++
++ return WriteV5ConnectRequest();
++}
++
++PRStatus
++nsSOCKSSocketInfo::WriteV5ConnectRequest()
++{
++ // Send SOCKS 5 connect request
++ PRNetAddr *addr = &mDestinationAddr;
++ PRInt32 proxy_resolve;
++ proxy_resolve = mFlags & nsISocketProvider::PROXY_RESOLVES_HOST;
++
++ LOGDEBUG(("socks5: sending connection request (socks5 resolve? %s)",
++ proxy_resolve? "yes" : "no"));
++
++ mDataLength = 0;
++ mState = SOCKS5_WRITE_CONNECT_REQUEST;
++
++ WriteUint8(0x05); // version -- 5
++ WriteUint8(0x01); // command -- connect
++ WriteUint8(0x00); // reserved
++
++ // Add the address to the SOCKS 5 request. SOCKS 5 supports several
++ // address types, so we pick the one that works best for us.
++ if (proxy_resolve) {
++ // Add the host name. Only a single byte is used to store the length,
++ // so we must prevent long names from being used.
++ if (mDestinationHost.Length() > MAX_HOSTNAME_LEN) {
++ LOGERROR(("socks5: destination host name is too long!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++ WriteUint8(0x03); // addr type -- domainname
++ WriteUint8(mDestinationHost.Length()); // name length
++ WriteString(mDestinationHost);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ WriteUint8(0x01); // addr type -- IPv4
++ WriteNetAddr(addr);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ WriteUint8(0x04); // addr type -- IPv6
++ WriteNetAddr(addr);
++ } else {
++ LOGERROR(("socks5: destination address of unknown type!"));
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++
++ WriteNetPort(addr); // port
++
++ return PR_SUCCESS;
++}
++
++PRStatus
++nsSOCKSSocketInfo::ReadV5AddrTypeAndLength(PRUint8 *type, PRUint32 *len)
++{
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP ||
++ mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ "Invalid state!");
++ NS_ABORT_IF_FALSE(mDataLength >= 5,
++ "SOCKS 5 connection reply must be at least 5 bytes!");
++
++ // Seek to the address location
++ mReadOffset = 3;
++
++ *type = ReadUint8();
++
++ switch (*type) {
++ case 0x01: // ipv4
++ *len = 4 - 1;
++ break;
++ case 0x04: // ipv6
++ *len = 16 - 1;
++ break;
++ case 0x03: // fqdn
++ *len = ReadUint8();
++ break;
++ default: // wrong address type
++ LOGERROR(("socks5: wrong address type in connection reply!"));
++ return PR_FAILURE;
++ }
++
++ return PR_SUCCESS;
++}
++
++PRStatus
++nsSOCKSSocketInfo::ReadV5ConnectResponseTop()
++{
++ PRUint8 res;
++ PRUint32 len;
++
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_TOP,
++ "Invalid state!");
++ NS_ABORT_IF_FALSE(mDataLength == 5,
++ "SOCKS 5 connection reply must be exactly 5 bytes!");
++
++ LOGDEBUG(("socks5: checking connection reply"));
++
++ // Check version number
++ if (ReadUint8() != 0x05) {
++ LOGERROR(("socks5: unexpected version in the reply"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ }
++
++ // Check response
++ res = ReadUint8();
++ if (res != 0x00) {
++ PRErrorCode c = PR_CONNECT_REFUSED_ERROR;
++
++ switch (res) {
++ case 0x01:
++ LOGERROR(("socks5: connect failed: "
++ "01, General SOCKS server failure."));
++ break;
++ case 0x02:
++ LOGERROR(("socks5: connect failed: "
++ "02, Connection not allowed by ruleset."));
++ break;
++ case 0x03:
++ LOGERROR(("socks5: connect failed: 03, Network unreachable."));
++ c = PR_NETWORK_UNREACHABLE_ERROR;
++ break;
++ case 0x04:
++ LOGERROR(("socks5: connect failed: 04, Host unreachable."));
++ break;
++ case 0x05:
++ LOGERROR(("socks5: connect failed: 05, Connection refused."));
++ break;
++ case 0x06:
++ LOGERROR(("socks5: connect failed: 06, TTL expired."));
++ c = PR_CONNECT_TIMEOUT_ERROR;
++ break;
++ case 0x07:
++ LOGERROR(("socks5: connect failed: "
++ "07, Command not supported."));
++ break;
++ case 0x08:
++ LOGERROR(("socks5: connect failed: "
++ "08, Address type not supported."));
++ c = PR_BAD_ADDRESS_ERROR;
++ break;
++ default:
++ LOGERROR(("socks5: connect failed."));
++ break;
++ }
++
++ HandshakeFinished(c);
++ return PR_FAILURE;
++ }
++
++ if (ReadV5AddrTypeAndLength(&res, &len) != PR_SUCCESS) {
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++
++ mState = SOCKS5_READ_CONNECT_RESPONSE_BOTTOM;
++ WantRead(len + 2);
++
++ return PR_SUCCESS;
++}
++
++PRStatus
++nsSOCKSSocketInfo::ReadV5ConnectResponseBottom()
++{
++ PRUint8 type;
++ PRUint32 len;
++
++ NS_ABORT_IF_FALSE(mState == SOCKS5_READ_CONNECT_RESPONSE_BOTTOM,
++ "Invalid state!");
++
++ if (ReadV5AddrTypeAndLength(&type, &len) != PR_SUCCESS) {
++ HandshakeFinished(PR_BAD_ADDRESS_ERROR);
++ return PR_FAILURE;
++ }
++
++ NS_ABORT_IF_FALSE(mDataLength == 7+len,
++ "SOCKS 5 unexpected length of connection reply!");
++
++ LOGDEBUG(("socks5: loading source addr and port"));
++ // Read what the proxy says is our source address
++ switch (type) {
++ case 0x01: // ipv4
++ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET);
++ break;
++ case 0x04: // ipv6
++ ReadNetAddr(&mExternalProxyAddr, PR_AF_INET6);
++ break;
++ case 0x03: // fqdn (skip)
++ mReadOffset += len;
++ mExternalProxyAddr.raw.family = PR_AF_INET;
++ break;
++ }
++
++ ReadNetPort(&mExternalProxyAddr);
++
++ LOGDEBUG(("socks5: connected!"));
++ HandshakeFinished();
++
++ return PR_SUCCESS;
++}
++
++void
++nsSOCKSSocketInfo::SetConnectTimeout(PRIntervalTime to)
++{
++ mTimeout = to;
++}
++
++PRStatus
++nsSOCKSSocketInfo::DoHandshake(PRFileDesc *fd, PRInt16 oflags)
++{
++ LOGDEBUG(("socks: DoHandshake(), state = %d", mState));
++
++ switch (mState) {
++ case SOCKS_INITIAL:
++ return ConnectToProxy(fd);
++ case SOCKS_CONNECTING_TO_PROXY:
++ return ContinueConnectingToProxy(fd, oflags);
++ case SOCKS4_WRITE_CONNECT_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ WantRead(8);
++ mState = SOCKS4_READ_CONNECT_RESPONSE;
++ return PR_SUCCESS;
++ case SOCKS4_READ_CONNECT_RESPONSE:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV4ConnectResponse();
++
++ case SOCKS5_WRITE_AUTH_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ WantRead(2);
++ mState = SOCKS5_READ_AUTH_RESPONSE;
++ return PR_SUCCESS;
++ case SOCKS5_READ_AUTH_RESPONSE:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5AuthResponse();
++ case SOCKS5_WRITE_CONNECT_REQUEST:
++ if (WriteToSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++
++ // The SOCKS 5 response to the connection request is variable
++ // length. First, we'll read enough to tell how long the response
++ // is, and will read the rest later.
++ WantRead(5);
++ mState = SOCKS5_READ_CONNECT_RESPONSE_TOP;
++ return PR_SUCCESS;
++ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5ConnectResponseTop();
++ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
++ if (ReadFromSocket(fd) != PR_SUCCESS)
++ return PR_FAILURE;
++ return ReadV5ConnectResponseBottom();
++
++ case SOCKS_CONNECTED:
++ LOGERROR(("socks: already connected"));
++ HandshakeFinished(PR_IS_CONNECTED_ERROR);
++ return PR_FAILURE;
++ case SOCKS_FAILED:
++ LOGERROR(("socks: already failed"));
++ return PR_FAILURE;
++ }
++
++ LOGERROR(("socks: executing handshake in invalid state, %d", mState));
++ HandshakeFinished(PR_INVALID_STATE_ERROR);
++
++ return PR_FAILURE;
++}
++
++PRInt16
++nsSOCKSSocketInfo::GetPollFlags() const
++{
++ switch (mState) {
++ case SOCKS_CONNECTING_TO_PROXY:
++ return PR_POLL_EXCEPT | PR_POLL_WRITE;
++ case SOCKS4_WRITE_CONNECT_REQUEST:
++ case SOCKS5_WRITE_AUTH_REQUEST:
++ case SOCKS5_WRITE_CONNECT_REQUEST:
++ return PR_POLL_WRITE;
++ case SOCKS4_READ_CONNECT_RESPONSE:
++ case SOCKS5_READ_AUTH_RESPONSE:
++ case SOCKS5_READ_CONNECT_RESPONSE_TOP:
++ case SOCKS5_READ_CONNECT_RESPONSE_BOTTOM:
++ return PR_POLL_READ;
++ default:
++ break;
++ }
++
++ return 0;
++}
++
++inline void
++nsSOCKSSocketInfo::WriteUint8(PRUint8 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ mData[mDataLength] = v;
++ mDataLength += sizeof(v);
++}
++
++inline void
++nsSOCKSSocketInfo::WriteUint16(PRUint16 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, &v, sizeof(v));
++ mDataLength += sizeof(v);
++}
++
++inline void
++nsSOCKSSocketInfo::WriteUint32(PRUint32 v)
++{
++ NS_ABORT_IF_FALSE(mDataLength + sizeof(v) <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, &v, sizeof(v));
++ mDataLength += sizeof(v);
++}
++
++void
++nsSOCKSSocketInfo::WriteNetAddr(const PRNetAddr *addr)
++{
++ const char *ip = NULL;
++ PRUint32 len = 0;
++
++ if (PR_NetAddrFamily(addr) == PR_AF_INET) {
++ ip = (const char*)&addr->inet.ip;
++ len = sizeof(addr->inet.ip);
++ } else if (PR_NetAddrFamily(addr) == PR_AF_INET6) {
++ ip = (const char*)addr->ipv6.ip.pr_s6_addr;
++ len = sizeof(addr->ipv6.ip.pr_s6_addr);
++ }
++
++ NS_ABORT_IF_FALSE(ip != NULL, "Unknown address");
++ NS_ABORT_IF_FALSE(mDataLength + len <= BUFFER_SIZE,
++ "Can't write that much data!");
++
++ memcpy(mData + mDataLength, ip, len);
++ mDataLength += len;
++}
++
++void
++nsSOCKSSocketInfo::WriteNetPort(const PRNetAddr *addr)
++{
++ WriteUint16(PR_NetAddrInetPort(addr));
++}
++
++void
++nsSOCKSSocketInfo::WriteString(const nsACString &str)
++{
++ NS_ABORT_IF_FALSE(mDataLength + str.Length() <= BUFFER_SIZE,
++ "Can't write that much data!");
++ memcpy(mData + mDataLength, str.Data(), str.Length());
++ mDataLength += str.Length();
++}
++
++inline PRUint8
++nsSOCKSSocketInfo::ReadUint8()
++{
++ PRUint8 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint8!");
++ rv = mData[mReadOffset];
++ mReadOffset += sizeof(rv);
++ return rv;
++}
++
++inline PRUint16
++nsSOCKSSocketInfo::ReadUint16()
++{
++ PRUint16 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint16!");
++ memcpy(&rv, mData + mReadOffset, sizeof(rv));
++ mReadOffset += sizeof(rv);
++ return rv;
++}
++
++inline PRUint32
++nsSOCKSSocketInfo::ReadUint32()
++{
++ PRUint32 rv;
++ NS_ABORT_IF_FALSE(mReadOffset + sizeof(rv) <= mDataLength,
++ "Not enough space to pop a uint32!");
++ memcpy(&rv, mData + mReadOffset, sizeof(rv));
++ mReadOffset += sizeof(rv);
++ return rv;
++}
++
++void
++nsSOCKSSocketInfo::ReadNetAddr(PRNetAddr *addr, PRUint16 fam)
++{
++ PRUint32 amt;
++ const PRUint8 *ip = mData + mReadOffset;
++
++ addr->raw.family = fam;
++ if (fam == PR_AF_INET) {
++ amt = sizeof(addr->inet.ip);
++ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
++ "Not enough space to pop an ipv4 addr!");
++ memcpy(&addr->inet.ip, ip, amt);
++ } else if (fam == PR_AF_INET6) {
++ amt = sizeof(addr->ipv6.ip.pr_s6_addr);
++ NS_ABORT_IF_FALSE(mReadOffset + amt <= mDataLength,
++ "Not enough space to pop an ipv6 addr!");
++ memcpy(addr->ipv6.ip.pr_s6_addr, ip, amt);
++ }
++
++ mReadOffset += amt;
++}
++
++void
++nsSOCKSSocketInfo::ReadNetPort(PRNetAddr *addr)
++{
++ addr->inet.port = ReadUint16();
++}
++
++void
++nsSOCKSSocketInfo::WantRead(PRUint32 sz)
++{
++ NS_ABORT_IF_FALSE(mDataIoPtr == NULL,
++ "WantRead() called while I/O already in progress!");
++ NS_ABORT_IF_FALSE(mDataLength + sz <= BUFFER_SIZE,
++ "Can't read that much data!");
++ mAmountToRead = sz;
++}
++
++PRStatus
++nsSOCKSSocketInfo::ReadFromSocket(PRFileDesc *fd)
++{
++ PRInt32 rc;
++ const PRUint8 *end;
++
++ if (!mAmountToRead) {
++ LOGDEBUG(("socks: ReadFromSocket(), nothing to do"));
++ return PR_SUCCESS;
++ }
++
++ if (!mDataIoPtr) {
++ mDataIoPtr = mData + mDataLength;
++ mDataLength += mAmountToRead;
++ }
++
++ end = mData + mDataLength;
++
++ while (mDataIoPtr < end) {
++ rc = PR_Read(fd, mDataIoPtr, end - mDataIoPtr);
++ if (rc <= 0) {
++ if (rc == 0) {
++ LOGERROR(("socks: proxy server closed connection"));
++ HandshakeFinished(PR_CONNECT_REFUSED_ERROR);
++ return PR_FAILURE;
++ } else if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
++ LOGDEBUG(("socks: ReadFromSocket(), want read"));
++ }
++ break;
++ }
++
++ mDataIoPtr += rc;
++ }
++
++ LOGDEBUG(("socks: ReadFromSocket(), have %u bytes total",
++ unsigned(mDataIoPtr - mData)));
++ if (mDataIoPtr == end) {
++ mDataIoPtr = nsnull;
++ mAmountToRead = 0;
++ mReadOffset = 0;
++ return PR_SUCCESS;
++ }
++
++ return PR_FAILURE;
++}
++
++PRStatus
++nsSOCKSSocketInfo::WriteToSocket(PRFileDesc *fd)
++{
++ PRInt32 rc;
++ const PRUint8 *end;
++
++ if (!mDataLength) {
++ LOGDEBUG(("socks: WriteToSocket(), nothing to do"));
++ return PR_SUCCESS;
++ }
++
++ if (!mDataIoPtr)
++ mDataIoPtr = mData;
++
++ end = mData + mDataLength;
++
++ while (mDataIoPtr < end) {
++ rc = PR_Write(fd, mDataIoPtr, end - mDataIoPtr);
++ if (rc < 0) {
++ if (PR_GetError() == PR_WOULD_BLOCK_ERROR) {
++ LOGDEBUG(("socks: WriteToSocket(), want write"));
++ }
++ break;
++ }
++
++ mDataIoPtr += rc;
++ }
++
++ if (mDataIoPtr == end) {
++ mDataIoPtr = nsnull;
++ mDataLength = 0;
++ mReadOffset = 0;
++ return PR_SUCCESS;
++ }
++
++ return PR_FAILURE;
++}
+
+ static PRStatus
+-nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime /*timeout*/)
++nsSOCKSIOLayerConnect(PRFileDesc *fd, const PRNetAddr *addr, PRIntervalTime to)
+ {
++ PRStatus status;
++ PRNetAddr dst;
+
++ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (info == NULL) return PR_FAILURE;
++
++ if (PR_NetAddrFamily(addr) == PR_AF_INET6 &&
++ PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
++ const PRUint8 *srcp;
++
++ LOGDEBUG(("socks: converting ipv4-mapped ipv6 address to ipv4"));
++
++ // copied from _PR_ConvertToIpv4NetAddr()
++ PR_InitializeNetAddr(PR_IpAddrAny, 0, &dst);
++ srcp = addr->ipv6.ip.pr_s6_addr;
++ memcpy(&dst.inet.ip, srcp + 12, 4);
++ dst.inet.family = PR_AF_INET;
++ dst.inet.port = addr->ipv6.port;
++ } else {
++ memcpy(&dst, addr, sizeof(dst));
++ }
++
++ info->SetDestinationAddr(&dst);
++ info->SetConnectTimeout(to);
++
++ do {
++ status = info->DoHandshake(fd, -1);
++ } while (status == PR_SUCCESS && !info->IsConnected());
++
++ return status;
++}
++
++static PRStatus
++nsSOCKSIOLayerConnectContinue(PRFileDesc *fd, PRInt16 oflags)
++{
+ PRStatus status;
+
+ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
+ if (info == NULL) return PR_FAILURE;
+
+- // First, we need to look up our proxy...
+- const nsCString &proxyHost = info->ProxyHost();
++ do {
++ status = info->DoHandshake(fd, oflags);
++ } while (status == PR_SUCCESS && !info->IsConnected());
+
+- if (proxyHost.IsEmpty())
+- return PR_FAILURE;
++ return status;
++}
+
+- PRInt32 socksVersion = info->Version();
++static PRInt16
++nsSOCKSIOLayerPoll(PRFileDesc *fd, PRInt16 in_flags, PRInt16 *out_flags)
++{
++ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
++ if (info == NULL) return PR_FAILURE;
+
+- LOGDEBUG(("nsSOCKSIOLayerConnect SOCKS %u; proxyHost: %s.", socksVersion, proxyHost.get()));
+-
+- // Sync resolve the proxy hostname.
+- PRNetAddr proxyAddr;
+- nsCOMPtr<nsIDNSRecord> rec;
+- nsresult rv;
+- {
+- nsCOMPtr<nsIDNSService> dns = do_GetService(NS_DNSSERVICE_CONTRACTID);
+- if (!dns)
+- return PR_FAILURE;
+-
+- rv = dns->Resolve(proxyHost, 0, getter_AddRefs(rec));
+- if (NS_FAILED(rv))
+- return PR_FAILURE;
++ if (!info->IsConnected()) {
++ *out_flags = 0;
++ return info->GetPollFlags();
+ }
+
+- info->SetInternalProxyAddr(&proxyAddr);
+-
+- // For now, we'll do this as a blocking connect,
+- // but with nspr 4.1, the necessary functions to
+- // do a non-blocking connect will be available
+-
+- // Preserve the non-blocking state of the socket
+- PRBool nonblocking;
+- PRSocketOptionData sockopt;
+- sockopt.option = PR_SockOpt_Nonblocking;
+- status = PR_GetSocketOption(fd, &sockopt);
+-
+- if (PR_SUCCESS != status) {
+- LOGERROR(("PR_GetSocketOption() failed. status = %x.", status));
+- return status;
+- }
+-
+- // Store blocking option
+- nonblocking = sockopt.value.non_blocking;
+-
+- sockopt.option = PR_SockOpt_Nonblocking;
+- sockopt.value.non_blocking = PR_FALSE;
+- status = PR_SetSocketOption(fd, &sockopt);
+-
+- if (PR_SUCCESS != status) {
+- LOGERROR(("PR_SetSocketOption() failed. status = %x.", status));
+- return status;
+- }
+-
+- // Now setup sockopts, so we can restore the value later.
+- sockopt.option = PR_SockOpt_Nonblocking;
+- sockopt.value.non_blocking = nonblocking;
+-
+- // This connectWait should be long enough to connect to local proxy
+- // servers, but not much longer. Since this protocol negotiation
+- // uses blocking network calls, the app can appear to hang for a maximum
+- // of this time if the user presses the STOP button during the SOCKS
+- // connection negotiation. Note that this value only applies to the
+- // connecting to the SOCKS server: once the SOCKS connection has been
+- // established, the value is not used anywhere else.
+- PRIntervalTime connectWait = PR_SecondsToInterval(10);
+-
+- // Connect to the proxy server.
+- PRInt32 addresses = 0;
+- do {
+- rv = rec->GetNextAddr(info->ProxyPort(), &proxyAddr);
+- if (NS_FAILED(rv)) {
+- status = PR_FAILURE;
+- break;
+- }
+- ++addresses;
+- status = fd->lower->methods->connect(fd->lower, &proxyAddr, connectWait);
+- } while (PR_SUCCESS != status);
+-
+- if (PR_SUCCESS != status) {
+- LOGERROR(("Failed to TCP connect to the proxy server (%s): timeout = %d, status = %x, tried %d addresses.", proxyHost.get(), connectWait, status, addresses));
+- PR_SetSocketOption(fd, &sockopt);
+- return status;
+- }
+-
+-
+- // We are now connected to the SOCKS proxy server.
+- // Now we will negotiate a connection to the desired server.
+-
+- // External IP address returned from ConnectSOCKS5(). Not supported in SOCKS4.
+- PRNetAddr extAddr;
+- PR_InitializeNetAddr(PR_IpAddrNull, 0, &extAddr);
+-
+- NS_ASSERTION((socksVersion == 4) || (socksVersion == 5), "SOCKS Version must be selected");
+-
+- // Try to connect via SOCKS 5.
+- if (socksVersion == 5) {
+- rv = ConnectSOCKS5(fd, addr, &extAddr, connectWait);
+-
+- if (NS_FAILED(rv)) {
+- PR_SetSocketOption(fd, &sockopt);
+- return PR_FAILURE;
+- }
+-
+- }
+-
+- // Try to connect via SOCKS 4.
+- else {
+- rv = ConnectSOCKS4(fd, addr, connectWait);
+-
+- if (NS_FAILED(rv)) {
+- PR_SetSocketOption(fd, &sockopt);
+- return PR_FAILURE;
+- }
+-
+- }
+-
+-
+- info->SetDestinationAddr((PRNetAddr*)addr);
+- info->SetExternalProxyAddr(&extAddr);
+-
+- // restore non-blocking option
+- PR_SetSocketOption(fd, &sockopt);
+-
+- // we're set-up and connected.
+- // this socket can be used as normal now.
+-
+- return PR_SUCCESS;
++ return fd->lower->methods->poll(fd->lower, in_flags, out_flags);
+ }
+
+ static PRStatus
+ nsSOCKSIOLayerClose(PRFileDesc *fd)
+ {
+ nsSOCKSSocketInfo * info = (nsSOCKSSocketInfo*) fd->secret;
+ PRDescIdentity id = PR_GetLayersIdentity(fd);
+
+@@ -880,16 +1115,18 @@ nsSOCKSIOLayerAddToSocket(PRInt32 family
+
+
+ if (firstTime)
+ {
+ nsSOCKSIOLayerIdentity = PR_GetUniqueIdentity("SOCKS layer");
+ nsSOCKSIOLayerMethods = *PR_GetDefaultIOMethods();
+
+ nsSOCKSIOLayerMethods.connect = nsSOCKSIOLayerConnect;
++ nsSOCKSIOLayerMethods.connectcontinue = nsSOCKSIOLayerConnectContinue;
++ nsSOCKSIOLayerMethods.poll = nsSOCKSIOLayerPoll;
+ nsSOCKSIOLayerMethods.bind = nsSOCKSIOLayerBind;
+ nsSOCKSIOLayerMethods.acceptread = nsSOCKSIOLayerAcceptRead;
+ nsSOCKSIOLayerMethods.getsockname = nsSOCKSIOLayerGetName;
+ nsSOCKSIOLayerMethods.getpeername = nsSOCKSIOLayerGetPeerName;
+ nsSOCKSIOLayerMethods.accept = nsSOCKSIOLayerAccept;
+ nsSOCKSIOLayerMethods.listen = nsSOCKSIOLayerListen;
+ nsSOCKSIOLayerMethods.close = nsSOCKSIOLayerClose;
+
1
0
r24432: {website} tbbs finally done uploading. bump all of their versions on t (website/trunk/include)
by Erinn Clark 24 Mar '11
by Erinn Clark 24 Mar '11
24 Mar '11
Author: erinn
Date: 2011-03-24 10:56:13 +0000 (Thu, 24 Mar 2011)
New Revision: 24432
Modified:
website/trunk/include/versions.wmi
Log:
tbbs finally done uploading. bump all of their versions on the website.
Modified: website/trunk/include/versions.wmi
===================================================================
--- website/trunk/include/versions.wmi 2011-03-24 08:46:00 UTC (rev 24431)
+++ website/trunk/include/versions.wmi 2011-03-24 10:56:13 UTC (rev 24432)
@@ -19,28 +19,28 @@
<define-tag version-osx-ppc-stable whitespace=delete>0.2.1.30</define-tag>
<define-tag version-osx-ppc-alpha whitespace=delete>0.2.2.23-alpha</define-tag>
-<define-tag version-torbrowserbundle whitespace=delete>1.3.20</define-tag>
+<define-tag version-torbrowserbundle whitespace=delete>1.3.21</define-tag>
<define-tag version-torbrowser-tor whitespace=delete>0.2.1.30</define-tag>
<define-tag version-torbrowser-tor-components whitespace=delete>libevent-1.4.13, zlib-1.2.3, openssl-0.9.8p</define-tag>
-<define-tag version-torbrowser-firefox whitespace=delete>3.6.15</define-tag>
+<define-tag version-torbrowser-firefox whitespace=delete>3.6.16</define-tag>
<define-tag version-torbrowser-torbutton whitespace=delete>1.2.5</define-tag>
<define-tag version-torbrowser-polipo whitespace=delete>1.0.4.1</define-tag>
<define-tag version-torbrowser-pidgin whitespace=delete>2.7.5</define-tag>
<define-tag version-torbrowser-otr whitespace=delete>3.2</define-tag>
<define-tag version-torbrowser-vidalia whitespace=delete>0.2.10</define-tag>
-<define-tag version-torimbrowserbundle whitespace=delete>1.3.20</define-tag>
+<define-tag version-torimbrowserbundle whitespace=delete>1.3.21</define-tag>
-<define-tag version-torbrowserbundlelinux32 whitespace=delete>1.1.5</define-tag>
-<define-tag version-torbrowserbundlelinux64 whitespace=delete>1.1.5</define-tag>
+<define-tag version-torbrowserbundlelinux32 whitespace=delete>1.1.6</define-tag>
+<define-tag version-torbrowserbundlelinux64 whitespace=delete>1.1.6</define-tag>
<define-tag version-gnu-torbrowser-tor whitespace=delete>0.2.2.23-alpha</define-tag>
-<define-tag version-gnu-torbrowser-tor-components whitespace=delete>libevent-1.4.13, zlib-1.2.3, openssl-0.9.8p</define-tag>
-<define-tag version-gnu-torbrowser-firefox whitespace=delete>3.6.15</define-tag>
+<define-tag version-gnu-torbrowser-tor-components whitespace=delete>libevent-2.0.10, zlib-1.2.3, openssl-0.9.8p</define-tag>
+<define-tag version-gnu-torbrowser-firefox whitespace=delete>3.6.16</define-tag>
<define-tag version-gnu-torbrowser-torbutton whitespace=delete>1.2.5</define-tag>
<define-tag version-gnu-torbrowser-vidalia whitespace=delete>0.2.10</define-tag>
-<define-tag version-torbrowserbundleosx whitespace=delete>1.0.13</define-tag>
+<define-tag version-torbrowserbundleosx whitespace=delete>1.0.14</define-tag>
<define-tag version-osx-torbrowser-tor whitespace=delete>0.2.2.23-alpha</define-tag>
-<define-tag version-osx-torbrowser-firefox whitespace=delete>3.6.15</define-tag>
+<define-tag version-osx-torbrowser-firefox whitespace=delete>3.6.16</define-tag>
<define-tag version-osx-torbrowser-torbutton whitespace=delete>1.2.5</define-tag>
<define-tag version-osx-torbrowser-polipo whitespace=delete>1.0.4.1</define-tag>
<define-tag version-osx-torbrowser-vidalia whitespace=delete>0.2.10</define-tag>
1
0
r24431: {website} Fix MIME type of table-title-arrow-rtl.jpg (website/trunk/images)
by Robert Ransom 24 Mar '11
by Robert Ransom 24 Mar '11
24 Mar '11
Author: rransom
Date: 2011-03-24 08:46:00 +0000 (Thu, 24 Mar 2011)
New Revision: 24431
Modified:
website/trunk/images/table-title-arrow-rtl.jpg
Log:
Fix MIME type of table-title-arrow-rtl.jpg
Property changes on: website/trunk/images/table-title-arrow-rtl.jpg
___________________________________________________________________
Added: svn:mime-type
+ image/jpeg
1
0
r24430: {} Add the right table-title-arrow-rtl.jpg (website/trunk/images)
by Sebastian Hahn 24 Mar '11
by Sebastian Hahn 24 Mar '11
24 Mar '11
Author: sebastian
Date: 2011-03-24 08:29:06 +0000 (Thu, 24 Mar 2011)
New Revision: 24430
Added:
website/trunk/images/table-title-arrow-rtl.jpg
Log:
Add the right table-title-arrow-rtl.jpg
Added: website/trunk/images/table-title-arrow-rtl.jpg
===================================================================
--- website/trunk/images/table-title-arrow-rtl.jpg (rev 0)
+++ website/trunk/images/table-title-arrow-rtl.jpg 2011-03-24 08:29:06 UTC (rev 24430)
@@ -0,0 +1,37 @@
+����JFIFHH��C !"$"$��C��!�����-T�!1AQq��"7t������!"132BC��?�U�%��3��w����x�z_�R�����k�J^��כ��������G��q穙��Z�q��[�/uUU��:�矪���ˑ1�ֈc9dD�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� �D�;Z ��Lc�� ȱs{����������<}N�о�W�~���O"o����H��;}���P���(�vJ)�QM��l�Sd��%�(��E6J)�QM��l�Sd��%�(��E6J)�QM��l�Sd��%�(��E6J)�QM��l�Sd��%�(��E6J)�QM��l�Sd��%�(��E6J)�QM��l�Sd��%�(��>tr�����?,�ӌ�_�Q��n�U|��ԁ�{���?\�P�TUE쨽�P�r���� �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��a �H6
+��ctV�P�Q�u�G��嶩����#��-��Oz�������y��?
+��,����[n�SuҫMT��*EOeE��T����~>t��y^� �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+ �r
+7��c�1�8����u�:S����o$l>���
\ No newline at end of file
1
0
24 Mar '11
Author: runa
Date: 2011-03-24 08:11:45 +0000 (Thu, 24 Mar 2011)
New Revision: 24429
Removed:
website/trunk/images/table-title-arrow-rtl.jpg
Log:
something is wrong with this image
Deleted: website/trunk/images/table-title-arrow-rtl.jpg
===================================================================
--- website/trunk/images/table-title-arrow-rtl.jpg 2011-03-24 07:28:48 UTC (rev 24428)
+++ website/trunk/images/table-title-arrow-rtl.jpg 2011-03-24 08:11:45 UTC (rev 24429)
@@ -1,109 +0,0 @@
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml">
-
-
-
-
-
-
-
-
- <head>
- <title>
- Attachment – Tor Bug Tracker & Wiki
- </title>
- <link rel="search" href="/projects/tor/search" />
- <link rel="help" href="/projects/tor/wiki/TracGuide" />
- <link rel="alternate" href="/projects/tor/raw-attachment/ticket/2692/table-title-arrow-rtl.jpg" type="image/jpeg; charset=utf-8" title="Original Format" />
- <link rel="up" href="/projects/tor/ticket/2692" title="Ticket #2692" />
- <link rel="start" href="/projects/tor/wiki" />
- <link rel="stylesheet" href="/projects/tor/chrome/common/css/trac.css" type="text/css" /><link rel="stylesheet" href="/projects/tor/chrome/common/css/code.css" type="text/css" /><link rel="stylesheet" href="/projects/tor/chrome/tracwysiwyg/wysiwyg.css" type="text/css" />
- <link rel="tracwysiwyg.stylesheet" href="/projects/tor/chrome/common/css/trac.css" /><link rel="tracwysiwyg.stylesheet" href="/projects/tor/chrome/tracwysiwyg/editor.css" />
- <link rel="tracwysiwyg.base" href="/projects/tor" />
- <link rel="shortcut icon" href="/images/favicon.ico" type="image/x-icon" />
- <link rel="icon" href="/images/favicon.ico" type="image/x-icon" />
- <link type="application/opensearchdescription+xml" rel="search" href="/projects/tor/search/opensearch" title="Search Tor Bug Tracker & Wiki" />
- <script type="text/javascript" src="/projects/tor/chrome/common/js/jquery.js"></script><script type="text/javascript" src="/projects/tor/chrome/common/js/trac.js"></script><script type="text/javascript" src="/projects/tor/chrome/common/js/search.js"></script><script type="text/javascript" src="/projects/tor/chrome/tracwysiwyg/wysiwyg.js"></script><script type="text/javascript" src="/projects/tor/chrome/tracwysiwyg/wysiwyg-load.js"></script>
- <!--[if lt IE 7]>
- <script type="text/javascript" src="/projects/tor/chrome/common/js/ie_pre7_hacks.js"></script>
- <![endif]-->
- <link rel="stylesheet" type="text/css" href="/tor.css" />
- </head>
- <body>
- <div id="siteheader">
- </div>
- <div id="banner">
- <div id="header">
- <a id="logo" href="https://trac.torproject.org/"><img src="/images/tor-logo.png" alt="The Tor Project" /></a>
- </div>
- <form id="search" action="/projects/tor/search" method="get">
- <div>
- <label for="proj-search">Search:</label>
- <input type="text" id="proj-search" name="q" size="18" value="" />
- <input type="submit" value="Search" />
- </div>
- </form>
- <div id="metanav" class="nav">
- <ul>
- <li class="first"><a href="/projects/tor/login">Login</a></li><li><a href="/projects/tor/prefs">Preferences</a></li><li><a href="/projects/tor/wiki/TracGuide">Help/Guide</a></li><li><a href="/projects/tor/about">About Trac</a></li><li><a href="/projects/tor/register">Register</a></li><li class="last"><a href="/projects/tor/reset_password">Forgot your password?</a></li>
- </ul>
- </div>
- </div>
- <div id="mainnav" class="nav">
- <ul>
- <li class="first"><a href="/projects/tor/report">View Tickets</a></li><li><a href="https://gitweb.torproject.org/">Git</a></li><li><a href="https://svn.torproject.org/svn/">Subversion</a></li><li><a href="/projects/tor/roadmap">Roadmap</a></li><li><a href="/projects/tor/timeline">Timeline</a></li><li><a href="/projects/tor/wiki">Wiki</a></li><li><a href="/projects/tor/search">Search</a></li><li><a href="/projects/tor/stats">Stats</a></li><li class="last"><a href="/projects/tor/tags">Tags</a></li>
- </ul>
- </div>
- <div id="main">
- <div id="ctxtnav" class="nav">
- <h2>Context Navigation</h2>
- <ul>
- <li class="last first"><a href="/projects/tor/ticket/2692">Back to Ticket #2692</a></li>
- </ul>
- <hr />
- </div>
- <div id="content" class="attachment">
- <h1><a href="/projects/tor/ticket/2692">Ticket #2692</a>: table-title-arrow-rtl.jpg</h1>
- <table id="info" summary="Description">
- <tbody>
- <tr>
- <th scope="col">
- File table-title-arrow-rtl.jpg, <span title="1333 bytes">1.3 KB</span>
- (added by OsamaK, <a class="timeline" href="/projects/tor/timeline?from=2011-03-15T15%3A15%3A40Z&precision=second" title="2011-03-15T15:15:40Z in Timeline">28 hours</a> ago)
- </th>
- </tr>
- <tr>
- <td class="message searchable">
- <p>
-the flipped background
-</p>
-
- </td>
- </tr>
- </tbody>
- </table>
- <div id="preview" class="searchable">
- <div class="image-file"><img src="/projects/tor/raw-attachment/ticket/2692/table-title-arrow-rtl.jpg" alt="table-title-arrow-rtl.jpg" /></div>
- </div>
- </div>
- <div id="altlinks">
- <h3>Download in other formats:</h3>
- <ul>
- <li class="last first">
- <a rel="nofollow" href="/projects/tor/raw-attachment/ticket/2692/table-title-arrow-rtl.jpg">Original Format</a>
- </li>
- </ul>
- </div>
- </div>
- <div id="footer" lang="en" xml:lang="en"><hr />
- <a id="tracpowered" href="http://trac.edgewall.org/"><img src="/projects/tor/chrome/common/trac_logo_mini.png" height="30" width="107" alt="Trac Powered" /></a>
- <p class="left">
- Powered by <a href="/projects/tor/about"><strong>Trac 0.11.7</strong></a><br />
- By <a href="http://www.edgewall.org/">Edgewall Software</a>.
- </p>
- <p class="right">Visit the Tor project at<br /><a href="https://www.torproject.org/">https://www.torproject.org/</a></p>
- </div>
- <div id="sitefooter">
- </div>
- </body>
-</html>
\ No newline at end of file
1
0