replace contrib/auto-naming with a readme saying where it went

This commit is contained in:
Roger Dingledine 2009-09-19 06:22:50 -04:00
parent 6750f7e8b1
commit 2218fd22c5
9 changed files with 3 additions and 542 deletions

View File

@ -1,65 +1,6 @@
=== AUTONAMING FOR TOR ===
Tor directory authorities may maintain a binding of server identities Tor directory authorities may maintain a binding of server identities
(their long term identity key) and nicknames. In their status documents (their long term identity key) and nicknames.
they may for each router they know tell if this is indeed the owner of
that nickname or not.
This toolset allows automatic maintaining of a binding list of nicknames The auto-naming scripts have been moved to svn in
to identity keys, implementing Tor proposal 123[1]. projects/tor-naming/auto-naming/trunk/
The rules are simple:
- A router claiming to be Bob becomes named (i.e. added to the binding list)
if there currently does not exist a different binding for that
nickname, the router has been around for a bit (2 weeks), and no other
router has used that nickname in a while (1 month).
- A binding is removed if the server that owns it has not been seen
in a long time (6 months).
=== REQUIREMENTS ===
* ruby, and its postgres DBI interface (Debian packages: ruby, ruby1.8, libdbi-ruby1.8, libdbd-pg-ruby1.8)
* postgres (tested with >= 8.1)
* cron
=== SETUP ===
* copy this tree some place, like into a 'auto-naming' directory in your Tor's
data directory
* create a database and a user, modifying db-config.rb accordingly
* initialize the database by executing the sql statements in create-db.sql
* setup a cronjob that feeds the current consensus to the process-consensus
script regularly.
* once the database is sufficiently populated, maybe a month or so after the
previous step, setup a cronjob to regularly build the binding list using
the build-approved-routers script. You probably want to append a manually
managed list of rejections to that file and give it to tor as its
"approved-routers" file.
The Sample-Makefile and Sample-crontab demonstrate the method used at tor26.
1. https://tor-svn.freehaven.net/svn/tor/trunk/doc/spec/proposals/123-autonaming.txt
Copyright (c) 2007 Peter Palfrader
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -1,20 +0,0 @@
all: ../approved-routers
update:
wget -q -O - http://tor.noreply.org/tor/status-vote/current/consensus | \
./process-consensus
.PHONY: approved-routers-auto
approved-routers-auto:
./build-approved-routers > "$@"
.INTERMEDIATE: approved-routers
approved-routers: approved-routers-auto /etc/tor/approved-routers
cat $^ > "$@"
../approved-routers: approved-routers
if ! diff -q "$<" "$@"; then \
mv "$<" "$@" &&\
(! [ -e /var/run/tor/tor.pid ] || kill -HUP `cat /var/run/tor/tor.pid`) ; \
fi

View File

@ -1,3 +0,0 @@
MAILTO=admin
# cronjob for tor naming
23 * * * * make -s -C auto-naming update && make -s -C auto-naming

View File

@ -1,45 +0,0 @@
#!/usr/bin/ruby
# build-approved-routers - create a name-binding list for use at a Tor
# directory authority
#
# Copyright (c) 2007 Peter Palfrader
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require "yaml"
require 'db'
require 'db-config'
verbose = ARGV.first == "-v"
db = Db.new($CONFIG['database']['dbhost'], $CONFIG['database']['dbname'], $CONFIG['database']['user'], $CONFIG['database']['password'])
db.transaction_begin
named = db.query2("
SELECT fingerprint, router_id, nickname_id, nick, first_seen, last_seen
FROM router NATURAL JOIN router_claims_nickname NATURAL JOIN nickname
WHERE named")
while (n=named.next) do
puts "# (r##{n['router_id']},n##{n['nickname_id']}); first_seen: #{n['first_seen']}, last_seen: #{n['last_seen']}"
fpr = n['fingerprint'].split(/(....)/).delete_if{|x| x=="" }.join(' ')
puts "#{n['nick']} #{fpr}"
end
db.transaction_commit

View File

@ -1,50 +0,0 @@
CREATE TABLE router (
router_id SERIAL PRIMARY KEY,
fingerprint CHAR(40) NOT NULL,
UNIQUE(fingerprint)
);
-- already created implicitly due to unique contraint
-- CREATE INDEX router_fingerprint ON router(fingerprint);
CREATE TABLE nickname (
nickname_id SERIAL PRIMARY KEY,
nick VARCHAR(30) NOT NULL,
UNIQUE(nick)
);
-- already created implicitly due to unique contraint
-- CREATE INDEX nickname_nick ON nickname(nick);
CREATE TABLE router_claims_nickname (
router_id INTEGER NOT NULL REFERENCES router(router_id) ON DELETE CASCADE,
nickname_id INTEGER NOT NULL REFERENCES nickname(nickname_id) ON DELETE CASCADE,
first_seen TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
last_seen TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
named BOOLEAN NOT NULL DEFAULT 'false',
UNIQUE(router_id, nickname_id)
);
CREATE INDEX router_claims_nickname_router_id ON router_claims_nickname(router_id);
CREATE INDEX router_claims_nickname_nickname_id ON router_claims_nickname(nickname_id);
CREATE INDEX router_claims_nickname_first_seen ON router_claims_nickname(first_seen);
CREATE INDEX router_claims_nickname_last_seen ON router_claims_nickname(last_seen);
-- Copyright (c) 2007 Peter Palfrader
--
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-- copies of the Software, and to permit persons to whom the Software is
-- furnished to do so, subject to the following conditions:
--
-- The above copyright notice and this permission notice shall be included in
-- all copies or substantial portions of the Software.
--
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-- SOFTWARE.

View File

@ -1,8 +0,0 @@
$CONFIG = {} unless $CONFIG
$CONFIG['database'] = {} unless $CONFIG['database']
# if you use postgres' "ident sameuser" auth set dbhost to ''
$CONFIG['database']['dbhost'] = 'localhost';
$CONFIG['database']['dbname'] = 'tornaming';
$CONFIG['database']['user'] = 'tornaming';
$CONFIG['database']['password'] = 'x';

View File

@ -1,165 +0,0 @@
#!/usr/bin/ruby
# Copyright (c) 2006, 2007 Peter Palfrader
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require "dbi"
class WeaselDbQueryHandle
def initialize(sth)
@sth = sth
end
def next()
row = @sth.fetch_hash
if row
return row
else
@sth.finish
return nil
end
end
end
class Db
def initialize(host, database, user, password)
@dbh = DBI.connect("dbi:Pg:#{database}:#{host}", user, password);
@dbh['AutoCommit'] = false
@transaction = false
@pre_initial_transaction=true
end
def do(query,*args)
@dbh.do(query,*args)
end
def transaction_begin()
@dbh.do("BEGIN") unless @pre_initial_transaction
@transaction = true
@pre_initial_transaction=false
end
def transaction_commit()
@dbh.do("COMMIT")
@transaction = false
end
def transaction_rollback()
@dbh.do("ROLLBACK")
end
def get_primarykey_name(table);
#return 'ref';
return table+'_id';
end
def update(table, values, keys)
cols = []
vals = []
values.each_pair{ |k,v|
cols << "#{k}=?"
vals << v
}
wheres = []
keys.each_pair{ |k,v|
wheres << "#{k}=?"
vals << v
}
throw "update value set empty" unless cols.size > 0
throw "where clause empty" unless wheres.size > 0
query = "UPDATE #{table} SET #{cols.join(',')} WHERE #{wheres.join(' AND ')}"
transaction_begin unless transaction_before=@transaction
r = @dbh.do(query, *vals)
transaction_commit unless transaction_before
return r
end
def update_row(table, values)
pk_name = get_primarykey_name(table);
throw "Ref not defined" unless values[pk_name]
return update(table, values.clone.delete_if{|k,v| k == pk_name}, { pk_name => values[pk_name] });
end
def insert(table, values)
cols = values.keys
vals = values.values
qmarks = values.values.collect{ '?' }
query = "INSERT INTO #{table} (#{cols.join(',')}) VALUES (#{qmarks.join(',')})"
transaction_begin unless transaction_before=@transaction
@dbh.do(query, *vals)
transaction_commit unless transaction_before
end
def insert_row(table, values)
pk_name = get_primarykey_name(table);
if values[pk_name]
insert(table, values)
else
transaction_begin unless transaction_before=@transaction
row = query_row("SELECT nextval(pg_get_serial_sequence('#{table}', '#{pk_name}')) AS newref");
throw "No newref?" unless row['newref']
values[pk_name] = row['newref']
insert(table, values);
transaction_commit unless transaction_before
end
end
def delete_row(table, ref)
pk_name = get_primarykey_name(table);
query = "DELETE FROM #{table} WHERE #{pk_name}=?"
transaction_begin unless transaction_before=@transaction
@dbh.do(query, ref)
transaction_commit unless transaction_before
end
def query(query, *params)
sth = @dbh.execute(query, *params)
while row = sth.fetch_hash
yield row
end
sth.finish
end
# nil if no results
# hash if one match
# throw otherwise
def query_row(query, *params)
sth = @dbh.execute(query, *params)
row = sth.fetch_hash
if row == nil
sth.finish
return nil
elsif sth.fetch_hash != nil
sth.finish
throw "More than one result when querying for #{query}"
else
sth.finish
return row
end
end
def query_all(query, *params)
sth = @dbh.execute(query, *params)
rows = sth.fetch_all
return nil if rows.size == 0
return rows
end
def query2(query, *params)
sth = @dbh.execute(query, *params)
return WeaselDbQueryHandle.new(sth)
end
end

View File

@ -1,119 +0,0 @@
#!/usr/bin/ruby
# process-consensus - read a current consensus document, inserting the
# information into a database then calling
# update-named-status.rb to update the name-binding
# flags
#
# Copyright (c) 2007 Peter Palfrader
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require "yaml"
require 'db'
require 'db-config'
require 'update-named-status'
$db = Db.new($CONFIG['database']['dbhost'], $CONFIG['database']['dbname'], $CONFIG['database']['user'], $CONFIG['database']['password'])
$router_cache = {}
$nickname_cache = {}
def parse_consensus consensus
ts = nil
routers = []
consensus.each do |line|
(key, value) = line.split(' ',2)
case key
when "valid-after", "published": ts = DateTime.parse(value)
when "r":
(nick, fpr, _) = value.split(' ', 3)
nick.downcase!
next if nick == 'unnamed'
routers << {
'nick' => nick,
'fingerprint' => (fpr+'=').unpack('m').first.unpack('H*').first
}
end
end
throw "Did not find a timestamp" unless ts
throw "Did not find any routers" unless routers.size > 0
return ts, routers
end
def insert_routers_into_db(router, table, field, value)
pk = table+'_id'
row = $db.query_row("SELECT #{pk} FROM #{table} WHERE #{field}=?", value)
if row
return row[pk]
else
r = { field => value }
$db.insert_row( table, r )
return r[pk]
end
end
def handle_one_consensus(c)
puts "parsing..." if $verbose
timestamp, routers = parse_consensus c
puts "storing..." if $verbose
routers.each do |router|
fpr = router['fingerprint']
nick = router['nick']
$router_cache[fpr] = router_id = ($router_cache[fpr] or insert_routers_into_db(router, 'router', 'fingerprint', router['fingerprint']))
$nickname_cache[nick] = nickname_id = ($nickname_cache[nick] or insert_routers_into_db(router, 'nickname', 'nick', router['nick']))
row = $db.update(
'router_claims_nickname',
{ 'last_seen' => timestamp.to_s },
{ 'router_id' => router_id, 'nickname_id' => nickname_id} )
case row
when 0:
$db.insert('router_claims_nickname',
{
'first_seen' => timestamp.to_s,
'last_seen' => timestamp.to_s,
'router_id' => router_id, 'nickname_id' => nickname_id} )
when 1:
else
throw "Update of router_claims_nickname returned unexpected number of affected rows(#{row})"
end
end
end
$db.transaction_begin
if ARGV.first == '-v'
$verbose = true
ARGV.shift
end
if ARGV.size == 0
handle_one_consensus STDIN.readlines
do_update $verbose
else
ARGV.each do |filename|
puts filename if $verbose
handle_one_consensus File.new(filename).readlines
puts "updating..." if $verbose
do_update $verbose
end
end
$db.transaction_commit

View File

@ -1,70 +0,0 @@
#!/usr/bin/ruby
# update-named-status.rb - update the named status of routers in our database
#
# Copyright (c) 2007 Peter Palfrader
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
require "yaml"
require 'db'
require 'db-config'
def do_update(verbose)
now = $db.query_row("SELECT max(last_seen) AS max FROM router_claims_nickname")['max']
unless now
STDERR.puts "Could not find the latest last_seen timestamp. Is the database empty still?"
return
end
now = "TIMESTAMP '" + now.to_s + "'"
denamed = $db.do("
UPDATE router_claims_nickname
SET named=false
WHERE named
AND last_seen < #{now} - INTERVAL '6 months'")
puts "de-named: #{denamed}" if verbose
named = $db.do("
UPDATE router_claims_nickname
SET named=true
WHERE NOT named
AND first_seen < #{now} - INTERVAL '2 weeks'
AND last_seen > #{now} - INTERVAL '2 days'
AND NOT EXISTS (SELECT *
FROM router_claims_nickname AS innertable
WHERE named
AND router_claims_nickname.nickname_id=innertable.nickname_id) "+ # if that nickname is already named, we lose.
" AND NOT EXISTS (SELECT *
FROM router_claims_nickname AS innertable
WHERE router_claims_nickname.nickname_id=innertable.nickname_id
AND router_claims_nickname.router_id <> innertable.router_id
AND last_seen > #{now} - INTERVAL '1 month') ") # if nobody else wanted that nickname in the last month we are set
puts "named: #{named}" if verbose
end
if __FILE__ == $0
$db = Db.new($CONFIG['database']['dbhost'], $CONFIG['database']['dbname'], $CONFIG['database']['user'], $CONFIG['database']['password'])
verbose = ARGV.first == "-v"
$db.transaction_begin
do_update verbose
$db.transaction_commit
end