1#!/usr/bin/env ruby 2 3require 'rubygems' 4require 'bundler/setup' 5require 'json' 6require 'thread' 7require 'webrick' 8require './unittest' 9 10class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet 11 def initialize(server, dnsbackend) 12 @dnsbackend = dnsbackend 13 @semaphore = Mutex.new 14 @f = File.open("/tmp/remotebackend.txt.#{$$}","ab") 15 @f.set_encoding 'UTF-8' 16 end 17 18 def parse_arrays(params) 19 newparams = {} 20 params.each do |key,val| 21 if key=~/^(.*)\[(.*)\]\[(.*)\]/ 22 newparams[$1] = {} unless newparams.has_key? $1 23 newparams[$1][$2] = {} unless newparams[$1].has_key? $2 24 newparams[$1][$2][$3] = val 25 params.delete key 26 elsif key=~/^(.*)\[(.*)\]/ 27 if $2 == "" 28 newparams[$1] = [] unless newparams.has_key? $1 29 newparams[$1] << val 30 else 31 newparams[$1] = {} unless newparams.has_key? $1 32 newparams[$1][$2] = val 33 end 34 params.delete key 35 end 36 end 37 params.merge newparams 38 end 39 40 def parse_url(url) 41 url = url.split('/') 42 method = url.shift.downcase 43 44 # do some determining based on method names 45 args = case method 46 when "lookup" 47 { 48 "qname" => url.shift, 49 "qtype" => url.shift 50 } 51 when "list" 52 { 53 "id" => url.shift, 54 "zonename" => url.shift 55 } 56 when "getbeforeandafternamesabsolute", "getbeforeandafternames" 57 { 58 "id" => url.shift.to_i, 59 "qname" => url.shift 60 } 61 when "getdomainmetadata", "setdomainmetadata", "getdomainkeys" 62 { 63 "name" => url.shift, 64 "kind" => url.shift 65 } 66 when "removedomainkey", "activatedomainkey", "deactivatedomainkey" 67 { 68 "id" => url.shift.to_i, 69 "name" => url.shift 70 } 71 when "adddomainkey", "gettsigkey", "getdomaininfo", "settsigkey", "deletetsigkey", "getalldomainmetadata" 72 { 73 "name" => url.shift 74 } 75 when "setnotified", "feedents" 76 { 77 "id" => url.shift.to_i 78 } 79 when "ismaster" 80 { 81 "name" => url.shift, 82 "ip" => url.shift 83 } 84 when "supermasterbackend", "createslavedomain" 85 { 86 "ip" => url.shift, 87 "domain" => url.shift 88 } 89 when "feedents3" 90 { 91 "id" => url.shift.to_i, 92 "domain" => url.shift 93 } 94 when "starttransaction" 95 { 96 "id" => url.shift.to_i, 97 "domain" => url.shift, 98 "trxid" => url.shift.to_i 99 } 100 when "committransaction", "aborttransaction" 101 { 102 "trxid" => url.shift.to_i 103 } 104 when "replacerrset" 105 { 106 "id" => url.shift.to_i, 107 "qname" => url.shift, 108 "qtype" => url.shift 109 } 110 else 111 {} 112 end 113 114 [method, args] 115 end 116 117 def do_GET(req,res) 118 req.continue 119 120 tmp = req.path[/dns\/(.*)/,1] 121 return 400, "Bad request" if (tmp.nil?) 122 123 method, args = parse_url(tmp) 124 125 method = "do_#{method}" 126 127 # get more arguments 128 req.each do |k,v| 129 attr = k[/X-RemoteBackend-(.*)/,1] 130 if attr 131 args[attr] = v 132 end 133 end 134 135 args = args.merge req.query 136 137 if method == "do_adddomainkey" 138 args["key"] = { 139 "flags" => args.delete("flags").to_i, 140 "active" => args.delete("active").to_i, 141 "published" => args.delete("published").to_i, 142 "content" => args.delete("content") 143 } 144 end 145 146 args = parse_arrays args 147 begin 148 @f.puts "#{Time.now.to_f} [http]: #{({:method=>method,:parameters=>args}).to_json}" 149 rescue Encoding::UndefinedConversionError 150 # this fails with encoding error for feedEnts3 151 end 152 153 @semaphore.synchronize do 154 if @dnsbackend.respond_to?(method.to_sym) 155 result, log = @dnsbackend.send(method.to_sym, args) 156 body = {:result => result, :log => log} 157 res.status = 200 158 res["Content-Type"] = "application/javascript; charset=utf-8" 159 res.body = body.to_json 160 else 161 res.status = 404 162 res["Content-Type"] = "application/javascript; charset=utf-8" 163 res.body = ({:result => false, :log => ["Method not found"]}).to_json 164 end 165 166 @f.puts "#{Time.now.to_f} [http]: #{res.body}" 167 end 168 end 169 170 def do_DELETE(req,res) 171 do_GET(req,res) 172 end 173 174 def do_POST(req,res) 175 do_GET(req,res) 176 end 177 178 def do_PATCH(req,res) 179 do_GET(req,res) 180 end 181 182 def do_PUT(req,res) 183 do_GET(req,res) 184 end 185end 186 187server = WEBrick::HTTPServer.new( 188 :Port=>62434, 189 :BindAddress=>"localhost", 190# Logger: WEBrick::Log.new("remotebackend-server.log"), 191 :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ] 192) 193 194be = Handler.new 195server.mount "/dns", DNSBackendHandler, be 196server.mount_proc("/ping"){ |req,resp| resp.body = "pong" } 197 198trap('INT') { server.stop } 199trap('TERM') { server.stop } 200 201server.start 202