diff options
Diffstat (limited to 'contrib/auto-naming')
-rwxr-xr-x | contrib/auto-naming/build-approved-routers | 22 | ||||
-rw-r--r-- | contrib/auto-naming/create-db.sql | 29 | ||||
-rw-r--r-- | contrib/auto-naming/db-config.rb | 6 | ||||
-rw-r--r-- | contrib/auto-naming/db.rb | 145 | ||||
-rwxr-xr-x | contrib/auto-naming/process-consensus | 94 | ||||
-rwxr-xr-x | contrib/auto-naming/update-named-status.rb | 43 |
6 files changed, 339 insertions, 0 deletions
diff --git a/contrib/auto-naming/build-approved-routers b/contrib/auto-naming/build-approved-routers new file mode 100755 index 0000000000..dcc597e6f8 --- /dev/null +++ b/contrib/auto-naming/build-approved-routers @@ -0,0 +1,22 @@ +#!/usr/bin/ruby + +require "yaml" + +require 'db' +require 'db-config' + +verbose = ARGV.first == "-v" + +db = Db.new($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 diff --git a/contrib/auto-naming/create-db.sql b/contrib/auto-naming/create-db.sql new file mode 100644 index 0000000000..6377be3ea6 --- /dev/null +++ b/contrib/auto-naming/create-db.sql @@ -0,0 +1,29 @@ + +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); diff --git a/contrib/auto-naming/db-config.rb b/contrib/auto-naming/db-config.rb new file mode 100644 index 0000000000..3cf2dbe32a --- /dev/null +++ b/contrib/auto-naming/db-config.rb @@ -0,0 +1,6 @@ +$CONFIG = {} unless $CONFIG +$CONFIG['database'] = {} unless $CONFIG['database'] + +$CONFIG['database']['dbname'] = 'tornaming'; +$CONFIG['database']['user'] = 'tornaming'; +$CONFIG['database']['password'] = 'x'; diff --git a/contrib/auto-naming/db.rb b/contrib/auto-naming/db.rb new file mode 100644 index 0000000000..706e81c391 --- /dev/null +++ b/contrib/auto-naming/db.rb @@ -0,0 +1,145 @@ +#!/usr/bin/ruby + +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(database, user, password) + @dbh = DBI.connect("dbi:Pg:#{database}:localhost", 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 diff --git a/contrib/auto-naming/process-consensus b/contrib/auto-naming/process-consensus new file mode 100755 index 0000000000..321b64dfbd --- /dev/null +++ b/contrib/auto-naming/process-consensus @@ -0,0 +1,94 @@ +#!/usr/bin/ruby + +require "yaml" + +require 'db' +require 'db-config' +require 'update-named-status' + +$db = Db.new($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 true +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 diff --git a/contrib/auto-naming/update-named-status.rb b/contrib/auto-naming/update-named-status.rb new file mode 100755 index 0000000000..8ff60ca685 --- /dev/null +++ b/contrib/auto-naming/update-named-status.rb @@ -0,0 +1,43 @@ +#!/usr/bin/ruby + +require "yaml" + +require 'db' +require 'db-config' + +def do_update verbose + now = "TIMESTAMP '" + $db.query_row("SELECT max(last_seen) AS max FROM router_claims_nickname")['max'].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']['dbname'], $CONFIG['database']['user'], $CONFIG['database']['password']) + verbose = ARGV.first == "-v" + + $db.transaction_begin + do_update verbose + $db.transaction_commit +end |