From 45e845bfba96e634a6a068777af88c17dee0822d Mon Sep 17 00:00:00 2001 From: Peter van Dijk Date: Tue, 19 Mar 2013 08:47:58 +0000 Subject: [PATCH] add example.rb sample script for remotebackend, thanks Aki git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@3130 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- modules/remotebackend/example.rb | 203 +++++++++++++++++++++++++++++++ 1 file changed, 203 insertions(+) create mode 100644 modules/remotebackend/example.rb diff --git a/modules/remotebackend/example.rb b/modules/remotebackend/example.rb new file mode 100644 index 000000000..031774a74 --- /dev/null +++ b/modules/remotebackend/example.rb @@ -0,0 +1,203 @@ +#!/usr/bin/ruby + +require 'rubygems' +require 'json' + +## this is an example stub for remote backend +## to add more methods, just write +## def do_(args) +## end +## look at the existing methods to find out +## how to customize this. + +## WARNING: this contains some code that +## should never be used in production, but +## is provided to give a more comprehensive +## example code. + +## Code provided only as example, not suitable +## for production. + +## Usage: +## launch=remote +## remote-dnssec=yes +## remote-connection-string=pipe:command=/path/to/example.rb,timeout=2000 + +class RequestHandler + +public + def initialize + @_log = [] + @initialized = false + @default_ttl = 3600 + end + +protected + + ## YOUR METHODS GO AFTER THIS LINE + + def do_initialize(args) + if @initialized + raise "Cannot reinitialize" + end + log "Example backend v1.0 starting" + @initialized = true + true + end + + ## used to tell that we do NSEC3 NARROW + def do_getdomainmetadata(args) + if args["name"] == "example.com" + if args["kind"] == "NSEC3NARROW" + return "1" + elsif args["kind"] == "NSEC3PARAM" + return "1 1 1 fe" + end + end + false + end + + ## returns keys, do not use in production + def do_getdomainkeys(args) + if args["name"] == "example.com" + return [ + { + "id" => 1, + "flags" => 257, + "active" => true, + "content" => "Private-key-format: v1.2 +Algorithm: 8 (RSASHA256) +Modulus: ovvzf1fHdptdXsBrBLSqmGqdEKwR2B9st/KBgh8xQKoQzTGUG00CsPjF/J59IBU+EU/IIInMn0MxLLTyUKa2DJUkR6i7UKif5jKX1c7yvWzrFKLGOHjugUX2++r+o789biUte1qpWp3Kc2RYL18oPco4zpo6JcsPmhOK3aUCDJXmuWgHl1KudCQIiPkISArXVn4oOp+skQq+mUBl1Pysc4D+6sl77ERR2fW6xJ4ZRPOIKr445RJJmKgoMG8yRrR3it1RmV49hZlvMosQjBUoNcqhqOI0n4l8HOLyna7KIzoNKG62GtUCZh8uy8IjdUiWPYGEtkZ9zE0bnnF+R7HGvQ== +PublicExponent: AQAB +PrivateExponent: Lp/c3IUD7o4re7uX4dS9KLT3EZnn0OfMdiLNoafCszjzbX/NWrIBHxdLrCS6rr7k7pbgLU6+VqEmJB/vYdsPITJZGpbOXxieBYBbpzJ4hm/uIA0gn28Y66pUKWTkS3ud2zCPfkZFREL3c2M1Rvf1zxdWgOPl1oHsiKsmgpl9qJOSKHMWFC+m/pUMJ7iOMgyDRV+PNeb/8P1jVOAYyQMEnu+enw2ro2NiWXNikbnaWrIv3IxVZAyZG4/H8+1vfQFPDWztosOy7OhV3WyMJkfwcXrlGoyLlxyAgkh/jeCnmPllxlJZGTgCtoVYd/n8osMXCDKxpAhsfdfCPeNOcjocgQ== +Prime1: +T+s7wv+zVqONJqkAKw4OCVzxBc5FWrmDPcjPCUeKIK/K/3+XjmIqTlbvBKf+7rm+AGVnXAbqk90+jzE3mKI8HMG/rM2cx01986xNQsIqwi2VAt25huPhEyrtNzos6lmrCYaioaQnNpMvMLun3DvcaygkDUXxH7Dg+6BTHeUfnk= +Prime2: p2YbBveBK3XyGMuVrDH9CvvpgKEoko+mPwLoKNpBoHrGxeOdCQmlPbnr0GrtZpy4sBNc5+shz2c6c1J3GlgPndT7zi2+MFGfWIGV48SAknVLfOU4iUpaGllnxcbjZeytG6WHdy2RaR3ReeGvdWxmxeuv084c2zC/7/vkcmgOqWU= +Exponent1: EdVFeUEBdQ3imM7rpwSrbRD47HHA6tBgL1NLWRVKyBk6tloQ5gr1xS3Oa3FlsuwXdG0gmEgaIqBWvUS1zTd9lr6UJIsL/UZ8wwMt2J62ew4/hVngouwb45pcuq8HkzsulmiPg5PHKwHPdb34tr2s1BRG1KqHzc5IDNt2stLnc/k= +Exponent2: oT+Iv1BAu7WUa/AHj+RjJGZ+iaozo+H9uOq66Uc8OjKqMErNpLwG0Qu7rHqjjdlfSjSMpNXpLpj4Q8fm9JhpCpbzq6qCbpbhUGcbFFjfpLSZ74f5yr21R3ZhsLChsTenlF8Bu3pIfKH9e1M7KXgvE22xY+xB/Z3a9XeFmfLEVMU= +Coefficient: vG8tLZBE4s3bftN5INv2/o3knEcaoUAPfakSsjM2uLwQCGiUbBOOlp3QSdTU4MiLjDsza3fKIptdwYP9PvSkhGhtLPjBpKjRk1J1+sct3dfT66JPClJc1A8bLQPj4ZpO/BkJe6ji4HYfOp7Rjn9z8rTqwEfbP64CZV3/frUzIkQ=" + }, + { + "id" => 2, + "flags" => 256, + "active" => true, + "content" => "Private-key-format: v1.2 +Algorithm: 8 (RSASHA256) +Modulus: wKPNcDwkCd2DKxfdkMqTFOV2ITdgxIDaOd4vQ2QtphMBY9yYwmEkNsVdVFz7VVuQHdls20JUe+brFUhs1zEMMbokulFP/qVAItAeEWcqtkPULT+mmX5HsexpFVAZ5+UXuerObk/HMiIMt1CvkIWhmjSIkAI6dFRlf/93zTjy0+vwrNWZPXSzLccK5TfJmxdYdGPcsHkg6UmqEFPQuyZpmlmpg3IwjL5YddTDobAoABz/BrH7WsW0q/PyVubITo8JuFiBI5Fmw+3ef3PVUt1jtUCGASvtqNXW4wtWrgqvQKg/odthpceQ4QagV9XSlOdml527thnf9cMpm0Gh4Ox5HQ== +PublicExponent: AQAB +PrivateExponent: f+M+26fRdQstrUomuZ0Cj/jVt69/+nRga9JpJiA3fe1YGue0MjczR3k3QG6KHFyxDF/vuJAMbkUbBAIU37ecFNcy0s5wgOlL7tCjZYJMBLx6+58qBvSivCfqi0+mIyEf4zlS2kD0SP/52SkjpJpScoE1uAUCsX/l8lezPPb1nmH3RDwJwX1NVhsErHCAmxGDoj4nPCEhKgHkdbR0i8geXGdWR4slyq1EhuGJal4p5sNvzDQTYRy6r49rpbNHw9F7ojomIhTUCUjOXAX0X1HB5UTXRMpgpCNEjRG1a+aqxp/ZSMHSEGCv67fua5Qrd/qX1Ppns/oqZfCfTpTD3v/sMQ== +Prime1: +0zQuFi7rZDTMGMIKiF6UOG5+pKwGxHmgKPOGF6fk3tIuSomgiVD3DLz5Y6kYk0kKls6IiA6X2esYwNXAaLe0dyMzpAnU4URXhFW7fUnHP0zA7NmaFRYPHstPeU59/JS+zmVlj4Ok1oeGocSGAFYGxXa+Sot0fyCXpAjZboDWg8= +Prime2: xD4hprQmcn5gmLqYO9+nEEJTNyNccbAciiKjRJxIE7w6muuKESx0uUn5XdnzSxhbVkK16kkEqW3s+Y+VoLxwRj2fuvoPfx8nTQXY1esgcIZCG8ubvHW5T0bzee5gyX3cMvaxkoeM7euYgvh0UwR/FG910SwAlmMZjSwXay2YlhM= +Exponent1: 6vcWzNcCnDWmkT53WtU0hb2Y4+YVzSm+iRcf039d20rRY3g6y0NGoPPvQftOTi9smkH0KAZULfJEp8tupbQAfN6ntVfpvVjVNUwnKJUo/hzsfxBVt0Ttv5c4ZQAYZHHqDsX3zKO3gyUmso0KaPGQzLpxpLlAYG+mAf7paeszyRc= +Exponent2: ouvWMjk0Bi/ncETRqDuYzkXSIl+oGvaT6xawp4B70m6d1QohWPqoeT/x2Dne44R4J9hAgR5X0XXinJnZJlXrfFUi7C84eFhb33UwPQD0sJa2Aa97Pu4Zh7im4J7IGd/01Ra7+6Ovm8LRnkI5CMcd3dBfZuX6IuBpUSu+0YtMN6M= +Coefficient: 5lP9IFknvFgaXKCs8MproehHSFhFTWac4557HIn03KrnlGOKDcY6DC/vgu1e42bEZ4J0RU0EELp5u4tAEYcumIaIVhfzRsajYRGln2mHe6o6nTO+FbANKuhyVmBEvTVczPOcYLrFXKVTglKAs+8W96dYIMDhiAwxi9zijLKKQ1k=" + } + ] + end + false + end + + ## Example lookup + ## Returns SOA, MX, NS and A records for example.com + ## also static A record for test.example.com + ## and dynamic A record for anything else in example.com domain + def do_lookup(args) + if args["qname"] == "example.com" and args["qtype"].downcase == "soa" + return [ + record("SOA","example.com", "sns.dns.icann.org noc.dns.icann.org 2013012485 7200 3600 1209600 3600"), + ] + elsif args["qname"] == "example.com" and args["qtype"].downcase == "any" + return [ + record("SOA","example.com", "sns.dns.icann.org noc.dns.icann.org 2013012485 7200 3600 1209600 3600"), + record("NS","example.com","sns.dns.icann.org"), + record_prio("MX","example.com","test.example.com",10) + ] + elsif args["qname"] == "test.example.com" and args["qtype"].downcase == "any" + return [ + record("A","test.example.com","127.0.0.1") + ] + elsif args["qname"] =~ /(.*)\.example\.com$/ and args["qtype"].downcase == "any" + ip = 0 + $1.downcase.each_byte do |b| ip = ip + b end + ip_2 = ip/256 + ip = ip%256 + return [ + record("A",args["qname"], "127.0.#{ip_2}.#{ip}") + ] + end + false + end + + ## AXFR support + ## Do note that having AXFR here is somewhat stupid since + ## we generate records above. But it is still included + ## for sake of having an example. Do not do ths in production. + def do_list(args) + if args["zonename"] == "example.com" + return [ + record("SOA","example.com", "sns.dns.icann.org noc.dns.icann.org 2013012485 7200 3600 1209600 3600"), + record("NS","example.com","sns.dns.icann.org"), + record_prio("MX","example.com","test.example.com",10), + record("A","test.example.com","127.0.0.1") + ] + end + false + end + + ## Please see http://doc.powerdns.com/remotebackend.html for methods to add here + ## Just remember to prefix them with do_ + + ## Some helpers after this + + def record_prio_ttl(qtype,qname,content,prio,ttl) + {:qtype => qtype, :qname => qname, :content => content, :priority => prio, :ttl => ttl, :auth => 1} + end + + def record_prio(qtype,qname,content,prio) + record_prio_ttl(qtype,qname,content,prio,@default_ttl) + end + + def record(qtype,qname,content) + record_prio_ttl(qtype,qname,content,0,@default_ttl) + end + + def log(message) + @_log << message + end + + ## Flushes log array and returns it. + def consume_log + ret = @_log + @_log = [] + ret + end + +public + def run + STDOUT.sync=true + STDIN.each_line do |line| + # So far rapidjson has managed to follow RFC4627 + # and hasn't done formatted json so there should be + # no newlines. + msg = JSON.parse(line) + + # it's a good idea to prefix methods with do_ to prevent + # clashes with initialize et al, and downcase it for simplicity + method = "do_#{msg["method"].downcase}".to_sym + if self.respond_to? method + result = self.send method, msg["parameters"] + else + log "Method #{msg["method"]} not implemented" + result = false + end + # build and emit result + reply = { :result => result, :log => consume_log } + puts reply.to_json + end + end +end + +begin + RequestHandler.new.run +rescue Interrupt + # ignore this exception, caused by ctrl+c in foreground mode +end -- 2.40.0