knot-ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 04ae67be521fbc10dc42972c8b3c7bfc9c0edc2822617a0ef565564e7e93bd6f
4
+ data.tar.gz: 89396bbc12e9aa181dcbf4af502262d4e8a4fb3ea982c28034c54d374078bd99
5
+ SHA512:
6
+ metadata.gz: 8cf55c28b347d9f5103451ad60d0da577c1febf8909b10bd30449985057c7d8640777953de99ff5509736ead73b8a8f5a9329150948f1a2dea9c30e55728c738
7
+ data.tar.gz: 826ffdff42cbf5a3dd7fc0a54707796c283d13eb0e99478c293ac620cf4b179c24393f0c2db2638717904d7aec0ef097dda2c1cb3d566ad81ebfe43273e8b53c
@@ -0,0 +1,154 @@
1
+ # ruby
2
+ /.bundle/
3
+ /.yardoc
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ /Gemfile.lock
12
+
13
+ # ---> Vim
14
+ # Swap
15
+ [._]*.s[a-v][a-z]
16
+ !*.svg # comment out if you don't need vector files
17
+ [._]*.sw[a-p]
18
+ [._]s[a-rt-v][a-z]
19
+ [._]ss[a-gi-z]
20
+ [._]sw[a-p]
21
+
22
+ # Session
23
+ Session.vim
24
+ Sessionx.vim
25
+
26
+ # Temporary
27
+ .netrwhist
28
+ *~
29
+ # Auto-generated tag files
30
+ tags
31
+ # Persistent undo
32
+ [._]*.un~
33
+
34
+ # ---> Kate
35
+ # Swap Files #
36
+ .*.kate-swp
37
+ .swp.*
38
+
39
+ # ---> KDevelop4
40
+ *.kdev4
41
+ .kdev4/
42
+
43
+ # ---> Emacs
44
+ # -*- mode: gitignore; -*-
45
+ *~
46
+ \#*\#
47
+ /.emacs.desktop
48
+ /.emacs.desktop.lock
49
+ *.elc
50
+ auto-save-list
51
+ tramp
52
+ .\#*
53
+
54
+ # Org-mode
55
+ .org-id-locations
56
+ *_archive
57
+
58
+ # flymake-mode
59
+ *_flymake.*
60
+
61
+ # eshell files
62
+ /eshell/history
63
+ /eshell/lastdir
64
+
65
+ # elpa packages
66
+ /elpa/
67
+
68
+ # reftex files
69
+ *.rel
70
+
71
+ # AUCTeX auto folder
72
+ /auto/
73
+
74
+ # cask packages
75
+ .cask/
76
+ dist/
77
+
78
+ # Flycheck
79
+ flycheck_*.el
80
+
81
+ # server auth directory
82
+ /server/
83
+
84
+ # projectiles files
85
+ .projectile
86
+
87
+ # directory configuration
88
+ .dir-locals.el
89
+
90
+ # network security
91
+ /network-security.data
92
+
93
+
94
+ # ---> Eclipse
95
+ .metadata
96
+ bin/
97
+ tmp/
98
+ *.tmp
99
+ *.bak
100
+ *.swp
101
+ *~.nib
102
+ local.properties
103
+ .settings/
104
+ .loadpath
105
+ .recommenders
106
+
107
+ # External tool builders
108
+ .externalToolBuilders/
109
+
110
+ # Locally stored "Eclipse launch configurations"
111
+ *.launch
112
+
113
+ # PyDev specific (Python IDE for Eclipse)
114
+ *.pydevproject
115
+
116
+ # CDT-specific (C/C++ Development Tooling)
117
+ .cproject
118
+
119
+ # CDT- autotools
120
+ .autotools
121
+
122
+ # Java annotation processor (APT)
123
+ .factorypath
124
+
125
+ # PDT-specific (PHP Development Tools)
126
+ .buildpath
127
+
128
+ # sbteclipse plugin
129
+ .target
130
+
131
+ # Tern plugin
132
+ .tern-project
133
+
134
+ # TeXlipse plugin
135
+ .texlipse
136
+
137
+ # STS (Spring Tool Suite)
138
+ .springBeans
139
+
140
+ # Code Recommenders
141
+ .recommenders/
142
+
143
+ # Annotation Processing
144
+ .apt_generated/
145
+ .apt_generated_test/
146
+
147
+ # Scala IDE specific (Scala & Java development for Eclipse)
148
+ .cache-main
149
+ .scala_dependencies
150
+ .worksheet
151
+
152
+ # ---> NotepadPP
153
+ # Notepad++ backups #
154
+ *.bak
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in knot.gemspec
4
+ gemspec
5
+
6
+ gem "rake", "~> 12.0"
data/LICENSE ADDED
@@ -0,0 +1,163 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+
3
+ Version 3, 29 June 2007
4
+
5
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
6
+
7
+ Everyone is permitted to copy and distribute verbatim copies of this license
8
+ document, but changing it is not allowed.
9
+
10
+ This version of the GNU Lesser General Public License incorporates the terms
11
+ and conditions of version 3 of the GNU General Public License, supplemented
12
+ by the additional permissions listed below.
13
+
14
+ 0. Additional Definitions.
15
+
16
+
17
+
18
+ As used herein, "this License" refers to version 3 of the GNU Lesser General
19
+ Public License, and the "GNU GPL" refers to version 3 of the GNU General Public
20
+ License.
21
+
22
+
23
+
24
+ "The Library" refers to a covered work governed by this License, other than
25
+ an Application or a Combined Work as defined below.
26
+
27
+
28
+
29
+ An "Application" is any work that makes use of an interface provided by the
30
+ Library, but which is not otherwise based on the Library. Defining a subclass
31
+ of a class defined by the Library is deemed a mode of using an interface provided
32
+ by the Library.
33
+
34
+
35
+
36
+ A "Combined Work" is a work produced by combining or linking an Application
37
+ with the Library. The particular version of the Library with which the Combined
38
+ Work was made is also called the "Linked Version".
39
+
40
+
41
+
42
+ The "Minimal Corresponding Source" for a Combined Work means the Corresponding
43
+ Source for the Combined Work, excluding any source code for portions of the
44
+ Combined Work that, considered in isolation, are based on the Application,
45
+ and not on the Linked Version.
46
+
47
+
48
+
49
+ The "Corresponding Application Code" for a Combined Work means the object
50
+ code and/or source code for the Application, including any data and utility
51
+ programs needed for reproducing the Combined Work from the Application, but
52
+ excluding the System Libraries of the Combined Work.
53
+
54
+ 1. Exception to Section 3 of the GNU GPL.
55
+
56
+ You may convey a covered work under sections 3 and 4 of this License without
57
+ being bound by section 3 of the GNU GPL.
58
+
59
+ 2. Conveying Modified Versions.
60
+
61
+ If you modify a copy of the Library, and, in your modifications, a facility
62
+ refers to a function or data to be supplied by an Application that uses the
63
+ facility (other than as an argument passed when the facility is invoked),
64
+ then you may convey a copy of the modified version:
65
+
66
+ a) under this License, provided that you make a good faith effort to ensure
67
+ that, in the event an Application does not supply the function or data, the
68
+ facility still operates, and performs whatever part of its purpose remains
69
+ meaningful, or
70
+
71
+ b) under the GNU GPL, with none of the additional permissions of this License
72
+ applicable to that copy.
73
+
74
+ 3. Object Code Incorporating Material from Library Header Files.
75
+
76
+ The object code form of an Application may incorporate material from a header
77
+ file that is part of the Library. You may convey such object code under terms
78
+ of your choice, provided that, if the incorporated material is not limited
79
+ to numerical parameters, data structure layouts and accessors, or small macros,
80
+ inline functions and templates (ten or fewer lines in length), you do both
81
+ of the following:
82
+
83
+ a) Give prominent notice with each copy of the object code that the Library
84
+ is used in it and that the Library and its use are covered by this License.
85
+
86
+ b) Accompany the object code with a copy of the GNU GPL and this license document.
87
+
88
+ 4. Combined Works.
89
+
90
+ You may convey a Combined Work under terms of your choice that, taken together,
91
+ effectively do not restrict modification of the portions of the Library contained
92
+ in the Combined Work and reverse engineering for debugging such modifications,
93
+ if you also do each of the following:
94
+
95
+ a) Give prominent notice with each copy of the Combined Work that the Library
96
+ is used in it and that the Library and its use are covered by this License.
97
+
98
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
99
+ document.
100
+
101
+ c) For a Combined Work that displays copyright notices during execution, include
102
+ the copyright notice for the Library among these notices, as well as a reference
103
+ directing the user to the copies of the GNU GPL and this license document.
104
+
105
+ d) Do one of the following:
106
+
107
+ 0) Convey the Minimal Corresponding Source under the terms of this License,
108
+ and the Corresponding Application Code in a form suitable for, and under terms
109
+ that permit, the user to recombine or relink the Application with a modified
110
+ version of the Linked Version to produce a modified Combined Work, in the
111
+ manner specified by section 6 of the GNU GPL for conveying Corresponding Source.
112
+
113
+ 1) Use a suitable shared library mechanism for linking with the Library. A
114
+ suitable mechanism is one that (a) uses at run time a copy of the Library
115
+ already present on the user's computer system, and (b) will operate properly
116
+ with a modified version of the Library that is interface-compatible with the
117
+ Linked Version.
118
+
119
+ e) Provide Installation Information, but only if you would otherwise be required
120
+ to provide such information under section 6 of the GNU GPL, and only to the
121
+ extent that such information is necessary to install and execute a modified
122
+ version of the Combined Work produced by recombining or relinking the Application
123
+ with a modified version of the Linked Version. (If you use option 4d0, the
124
+ Installation Information must accompany the Minimal Corresponding Source and
125
+ Corresponding Application Code. If you use option 4d1, you must provide the
126
+ Installation Information in the manner specified by section 6 of the GNU GPL
127
+ for conveying Corresponding Source.)
128
+
129
+ 5. Combined Libraries.
130
+
131
+ You may place library facilities that are a work based on the Library side
132
+ by side in a single library together with other library facilities that are
133
+ not Applications and are not covered by this License, and convey such a combined
134
+ library under terms of your choice, if you do both of the following:
135
+
136
+ a) Accompany the combined library with a copy of the same work based on the
137
+ Library, uncombined with any other library facilities, conveyed under the
138
+ terms of this License.
139
+
140
+ b) Give prominent notice with the combined library that part of it is a work
141
+ based on the Library, and explaining where to find the accompanying uncombined
142
+ form of the same work.
143
+
144
+ 6. Revised Versions of the GNU Lesser General Public License.
145
+
146
+ The Free Software Foundation may publish revised and/or new versions of the
147
+ GNU Lesser General Public License from time to time. Such new versions will
148
+ be similar in spirit to the present version, but may differ in detail to address
149
+ new problems or concerns.
150
+
151
+ Each version is given a distinguishing version number. If the Library as you
152
+ received it specifies that a certain numbered version of the GNU Lesser General
153
+ Public License "or any later version" applies to it, you have the option of
154
+ following the terms and conditions either of that published version or of
155
+ any later version published by the Free Software Foundation. If the Library
156
+ as you received it does not specify a version number of the GNU Lesser General
157
+ Public License, you may choose any version of the GNU Lesser General Public
158
+ License ever published by the Free Software Foundation.
159
+
160
+ If the Library as you received it specifies that a proxy can decide whether
161
+ future versions of the GNU Lesser General Public License shall apply, that
162
+ proxy's public statement of acceptance of any version is permanent authorization
163
+ for you to choose that version for the Library.
@@ -0,0 +1,46 @@
1
+ Knot
2
+ ====
3
+
4
+ Implements the knot-protocol.
5
+ It is possible to write a knot-cli like knotc in ruby.
6
+ Or your own tool, for provisioning.
7
+
8
+ Installation
9
+ ============
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ [source,ruby]
14
+ ----
15
+ gem 'knot'
16
+ ----
17
+
18
+ And then execute:
19
+
20
+ [source,sh]
21
+ -----
22
+ $ bundle install
23
+ -----
24
+
25
+ Or install it yourself as:
26
+
27
+ [source,sh]
28
+ -----
29
+ $ gem install knot-ruby
30
+ -----
31
+
32
+ Usage
33
+ -----
34
+
35
+ TODO: Write usage instructions here
36
+
37
+ Development
38
+ -----------
39
+
40
+ To install this gem onto your local machine, run `bundle exec rake install`.
41
+ To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
42
+
43
+ Contributing
44
+ ------------
45
+
46
+ Bug reports and pull requests are welcome at https://git.denkn.at/deac/knot-ruby.
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,31 @@
1
+ require_relative 'lib/knot/version'
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "knot-ruby"
5
+ spec.version = Knot::VERSION
6
+ spec.authors = ['Denis Knauf']
7
+ spec.email = ['gems+knot@denkn.at']
8
+ spec.licenses = ["LGPL-3.0"]
9
+
10
+ spec.summary = %q{Provides interface to knot-server.}
11
+ spec.description = %q{Implements knot-protocol to provide an interface to knot-DNS-server}
12
+ spec.homepage = 'https://git.denkn.at/deac/knot'
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
14
+
15
+ #spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = spec.homepage
19
+ spec.metadata["changelog_uri"] = spec.homepage
20
+
21
+ spec.add_dependency 'iounpack', '~> 0'
22
+
23
+ # Specify which files should be added to the gem when it is released.
24
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
25
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
26
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
27
+ end
28
+ spec.bindir = "bin"
29
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
30
+ spec.require_paths = ["lib"]
31
+ end
@@ -0,0 +1,4 @@
1
+ require 'knot/version'
2
+ require 'knot/errors'
3
+ require 'knot/protocol'
4
+ require 'knot/interface'
@@ -0,0 +1,166 @@
1
+ module Knot
2
+ class Error < ::Exception
3
+ attr_reader :Errno
4
+ attr_reader :Key
5
+ attr_reader :Errstr
6
+ end
7
+ end
8
+
9
+ module Knot::Errors
10
+ @num2exc = {}
11
+ @key2exc = {}
12
+ @err2exc = {}
13
+ class << self
14
+ attr_reader :num2exc, :key2exc, :err2exc
15
+
16
+ def array_arguments_with_typecheck *args
17
+ l = args.length
18
+ lambda do |a|
19
+ l == a.length and
20
+ args.zip(a).all? {|t,v| t === v }
21
+ end
22
+ end
23
+ end
24
+
25
+ def method_missing key
26
+ self[key]
27
+ end
28
+
29
+ def [] key_or_errno
30
+ case key_or_errno
31
+ when Integer
32
+ @num2exc[key_or_errno]
33
+ when Exception
34
+ key_or_errno
35
+ when Symbol
36
+ @key2exc[key_or_errno]
37
+ else
38
+ raise ArgumentError, "Invalid type. Expect Integer/Knot::Error/Symbol"
39
+ end
40
+ end
41
+
42
+ i = 0
43
+ [
44
+ [:EOK, 0, "OK"],
45
+ # Directly mapped error codes.
46
+ [:ENOMEM, -Errno::ENOMEM::Errno, "not enough memory" ],
47
+ [:EINVAL, -Errno::EINVAL::Errno, "invalid parameter" ],
48
+ [:ENOTSUP, -Errno::ENOTSUP::Errno, "operation not supported" ],
49
+ [:EBUSY, -Errno::EBUSY::Errno, "requested resource is busy" ],
50
+ [:EAGAIN, -Errno::EAGAIN::Errno, "OS lacked necessary resources" ],
51
+ [:EACCES, -Errno::EACCES::Errno, "operation not permitted" ],
52
+ [:ECONNREFUSED, -Errno::ECONNREFUSED::Errno, "connection refused" ],
53
+ [:EISCONN, -Errno::EISCONN::Errno, "already connected" ],
54
+ [:EADDRINUSE, -Errno::EADDRINUSE::Errno, "address already in use" ],
55
+ [:ENOENT, -Errno::ENOENT::Errno, "not exists" ],
56
+ [:EEXIST, -Errno::EEXIST::Errno, "already exists" ],
57
+ [:ERANGE, -Errno::ERANGE::Errno, "value is out of range" ],
58
+ [:EADDRNOTAVAIL, -Errno::EADDRNOTAVAIL::Errno, "address is not available" ],
59
+
60
+ # General errors.
61
+ [:ERROR, -1000, "failed"],
62
+ [:EPARSEFAIL, "parser failed"],
63
+ [:ESEMCHECK, "semantic check"],
64
+ [:EUPTODATE, "zone is up-to-date"],
65
+ [:EFEWDATA, "not enough data to parse"],
66
+ [:ESPACE, "not enough space provided"],
67
+ [:EMALF, "malformed data"],
68
+ [:ENSEC3PAR, "missing or wrong NSEC3PARAM record"],
69
+ [:ENSEC3CHAIN, "missing or wrong NSEC3 chain in the zone"],
70
+ [:EOUTOFZONE, "name does not belong to the zone"],
71
+ [:EZONEINVAL, "invalid zone file"],
72
+ [:ENOZONE, "no such zone found"],
73
+ [:ENONODE, "no such node in zone found"],
74
+ [:ENORECORD, "no such record in zone found"],
75
+ [:EISRECORD, "such record already exists in zone"],
76
+ [:ENOMASTER, "no usable master"],
77
+ [:EPREREQ, "UPDATE prerequisity not met"],
78
+ [:ETTL, "TTL mismatch"],
79
+ [:ENOXFR, "transfer was not sent"],
80
+ [:EDENIED, "not allowed"],
81
+ [:ECONN, "connection reset"],
82
+ [:ETIMEOUT, "connection timeout"],
83
+ [:ENODIFF, "cannot create zone diff"],
84
+ [:ENOTSIG, "expected a TSIG or SIG(0)"],
85
+ [:ELIMIT, "exceeded response rate limit"],
86
+ [:EZONESIZE, "zone size exceeded"],
87
+ [:EOF, "end of file"],
88
+ [:ESYSTEM, "system error"],
89
+ [:EFILE, "file error"],
90
+ [:ESOAINVAL, "SOA mismatch"],
91
+ [:ETRAIL, "trailing data"],
92
+ [:EPROCESSING, "processing error"],
93
+
94
+ # Control states.
95
+ [:CTL_ESTOP, "stopping server"],
96
+ # Network errors.
97
+ [:NET_EADDR, "bad address or host name"],
98
+ [:NET_ESOCKET, "can't create socket"],
99
+ [:NET_ECONNECT, "can't connect"],
100
+ [:NET_ESEND, "can't send data"],
101
+ [:NET_ERECV, "can't receive data"],
102
+ [:NET_ETIMEOUT, "network timeout"],
103
+ # Encoding errors.
104
+ [:BASE64_ESIZE, "invalid base64 string length"],
105
+ [:BASE64_ECHAR, "invalid base64 character"],
106
+ [:BASE32HEX_ESIZE, "invalid base32hex string length"],
107
+ [:BASE32HEX_ECHAR, "invalid base32hex character"],
108
+ # TSIG errors.
109
+ [:KNOT_TSIG_EBADSIG, "failed to verify TSIG"],
110
+ [:KNOT_TSIG_EBADKEY, "TSIG key not recognized or invalid"],
111
+ [:KNOT_TSIG_EBADTIME, "TSIG out of time window"],
112
+ [:KNOT_TSIG_EBADTRUNC, "TSIG bad truncation"],
113
+ # DNSSEC errors.
114
+ [:DNSSEC_ENOKEY, "no keys for signing"],
115
+ [:DNSSEC_EMISSINGKEYTYPE, "missing active KSK or ZSK"],
116
+ # Yparser errors.
117
+ [:YP_ECHAR_TAB, "tabulator character is not allowed"],
118
+ [:YP_EINVAL_ITEM, "invalid item"],
119
+ [:YP_EINVAL_ID, "invalid identifier"],
120
+ [:YP_EINVAL_DATA, "invalid value"],
121
+ [:YP_EINVAL_INDENT, "invalid indentation"],
122
+ [:YP_ENOTSUP_DATA, "value not supported"],
123
+ [:YP_ENOTSUP_ID, "identifier not supported"],
124
+ [:YP_ENODATA, "missing value"],
125
+ [:YP_ENOID, "missing identifier"],
126
+ # Configuration errors.
127
+ [:CONF_ENOTINIT, "config DB not initialized"],
128
+ [:CONF_EVERSION, "invalid config DB version"],
129
+ [:CONF_EREDEFINE, "duplicate identifier"],
130
+ # Transaction errors.
131
+ [:TXN_EEXISTS, "too many transactions"],
132
+ [:TXN_ENOTEXISTS, "no active transaction"],
133
+ # DNSSEC errors.
134
+ [:INVALID_PUBLIC_KEY, "invalid public key"],
135
+ [:INVALID_PRIVATE_KEY, "invalid private key"],
136
+ [:INVALID_KEY_ALGORITHM, "invalid key algorithm"],
137
+ [:INVALID_KEY_SIZE, "invalid key size"],
138
+ [:INVALID_KEY_ID, "invalid key ID"],
139
+ [:INVALID_KEY_NAME, "invalid key name"],
140
+ [:NO_PUBLIC_KEY, "no public key"],
141
+ [:NO_PRIVATE_KEY, "no private key"],
142
+ ].each do |v|
143
+ e = nil
144
+ case v
145
+ when array_arguments_with_typecheck( Symbol, String)
146
+ v, e = v
147
+ when array_arguments_with_typecheck( String, String)
148
+ v, e = v
149
+ v = v.to_sym
150
+ when array_arguments_with_typecheck( Symbol, Integer, String)
151
+ v, i, e = v
152
+ when array_arguments_with_typecheck( String, Integer, String)
153
+ v, i, e = v
154
+ v = v.to_sym
155
+ else
156
+ raise ArgumentError, "[Symbol, String] | [Symbol, Int, String] expected, not #{v}"
157
+ end
158
+ cl = Class.new Exception
159
+ cl.const_set :Key, v
160
+ cl.const_set :Errno, i
161
+ cl.const_set :Errstr, e
162
+ const_set v, cl
163
+ @num2exc[i] = @key2exc[v] = @err2exc[e] = cl
164
+ i += 1
165
+ end
166
+ end
@@ -0,0 +1,159 @@
1
+ require_relative 'protocol'
2
+ require_relative 'errors'
3
+
4
+ module Knot
5
+ end
6
+
7
+ class Knot::Zone
8
+ attr_reader :protocol, :zone
9
+ def initialize zone, protocol = nil
10
+ @protocol = protocol || Protocol.new
11
+ @zone, @transaction_opened = zone, 0
12
+ end
13
+
14
+ def begin
15
+ @transaction_opened += 1
16
+ @protocol.call command: 'zone-begin', zone: @zone if 1 == @transaction_opened
17
+ end
18
+
19
+ def commit
20
+ @protocol.call command: 'zone-commit', zone: @zone if 1 == @transaction_opened
21
+ @transaction_opened -= 1 if 0 < @transaction_opened
22
+ end
23
+
24
+ def abort
25
+ @protocol.call command: 'zone-abort', zone: @zone
26
+ @transaction_opened = 0
27
+ end
28
+
29
+ def transaction
30
+ self.begin
31
+ yield self
32
+ rescue Object
33
+ self.abort
34
+ raise
35
+ ensure
36
+ self.commit unless $!
37
+ end
38
+
39
+ # zone operation
40
+
41
+ def check() @protocol.call command: 'zone-check', zone: @zone end
42
+ def reload() @protocol.call command: 'zone-reload', zone: @zone end
43
+ def refresh() @protocol.call command: 'zone-refresh', zone: @zone end
44
+ def notify() @protocol.call command: 'zone-notify', zone: @zone end
45
+ def retransfer() @protocol.call command: 'zone-retransfer', zone: @zone end
46
+ def sign() @protocol.call command: 'zone-sign', zone: @zone end
47
+ def freeze() @protocol.call command: 'zone-freeze', zone: @zone end
48
+ def thaw() @protocol.call command: 'zone-thaw', zone: @zone end
49
+ def status( filter = nil) @protocol.call command: 'zone-status', zone: @zone, filter: filter end
50
+
51
+ def stats( modul = nil, counter = nil)
52
+ @protocol.call command: 'zone-stats', zone: @zone, module: modul, counter: counter
53
+ end
54
+
55
+ # zone manipulation
56
+
57
+ def read() @protocol.call command: 'zone-read', zone: @zone end
58
+ def diff() @protocol.call command: 'zone-diff', zone: @zone end
59
+
60
+ # setting record
61
+ # if data is nil, it will be unset.
62
+ def set owner, ttl = nil, type, data
63
+ @protocol.call command: data.nil? ? 'zone-unset' : 'zone-set',
64
+ zone: @zone, owner: owner, ttl: ttl, type: type, data: data
65
+ rescue Knot::Errors::EISRECORD, Knot::Errors::ENONODE, Knot::Errors::ENOENT
66
+ end
67
+ alias []= set
68
+
69
+ def unset owner, type = nil, data = nil
70
+ @protocol.call command: 'zone-unset',
71
+ zone: @zone, owner: owner, type: type, data: data
72
+ rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT
73
+ end
74
+ alias delete unset
75
+
76
+ def get owner = nil, type = nil
77
+ @protocol.call command: 'zone-get',
78
+ zone: @zone, owner: owner, type: type
79
+ rescue Knot::Errors::ENONODE, Knot::Errors::ENOENT
80
+ nil
81
+ end
82
+ alias [] get
83
+ end
84
+
85
+ class Knot::Conf
86
+ def initialize protocol = nil
87
+ @protocol = protocol || Protocol.new
88
+ @transaction_opened = 0
89
+ end
90
+
91
+ def begin
92
+ @transaction_opened += 1
93
+ @protocol.call command: 'conf-begin' if 1 == @transaction_opened
94
+ end
95
+
96
+ def commit
97
+ @protocol.call command: 'conf-commit' if 1 == @transaction_opened
98
+ @transaction_opened -= 1 if 0 < @transaction_opened
99
+ end
100
+
101
+ def abort
102
+ @protocol.call command: 'conf-abort'
103
+ @transaction_opened = 0
104
+ end
105
+
106
+ def transaction
107
+ self.begin
108
+ yield self
109
+ rescue Object
110
+ self.abort
111
+ raise
112
+ ensure
113
+ self.commit
114
+ end
115
+
116
+ def parse_item k
117
+ case k
118
+ when k
119
+ case k.keys.sort
120
+ when %w[section], %w[id section], %w[item section], %w[id item section] then k
121
+ else raise ArgumentError, "Invalid Item-format"
122
+ end
123
+
124
+ when Array
125
+ case k.length
126
+ when 1 then {section: k[0]}
127
+ when 2 then {section: k[0], item: k[1]}
128
+ when 3 then {section: k[0], id: k[1], item: k[2]}
129
+ else raise ArgumentError, "Invalid Item-format"
130
+ end
131
+
132
+ when /\A
133
+ (?<section> [a-z0-9_-]+ )
134
+ (?: \[ (?<id> [a-z0-9_.-]+) \] )?
135
+ (?: \. (?<item>[a-z0-9_-]+) )?
136
+ \z/xi
137
+ $~.named_captures.delete_if {|_,v| v.nil? }
138
+ else raise ArgumentError, "Invalid Item-format"
139
+ end
140
+ end
141
+
142
+ def set item, value
143
+ @protocol.call parse_item( item).update( command: 'conf-set', data: value)
144
+ end
145
+ alias [] set
146
+
147
+ def unset item, value = nil
148
+ @protocol.call parse_item( item).update( command: 'conf-unset', data: value)
149
+ end
150
+ alias delete unset
151
+
152
+ def list item = nil
153
+ @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-list')
154
+ end
155
+
156
+ def read item = nil
157
+ @protocol.call (item ? parse_item( item) : {}).update( command: 'conf-read')
158
+ end
159
+ end
@@ -0,0 +1,188 @@
1
+ require 'iounpack'
2
+ require_relative 'errors'
3
+
4
+ module Knot
5
+ class Protocol
6
+ end
7
+ end
8
+
9
+ module Knot::Protocol::Type
10
+ def [] code
11
+ case code
12
+ when 0, End then return End
13
+ when 1, Data then return Data
14
+ when 2, Extra then return Extra
15
+ when 3, Block then return Block
16
+ end
17
+ end
18
+
19
+ class Base
20
+ def self.expect_data?
21
+ false
22
+ end
23
+ def expect_data?() self.class.expect_data? end
24
+ def code() self.class.code end
25
+ end
26
+ class End < Base
27
+ def self.code() 0 end
28
+ end
29
+ class Data < Base
30
+ def code() 1 end
31
+ def expect_data?
32
+ true
33
+ end
34
+ attr_reader :data
35
+ def initialize data
36
+ @data = data
37
+ end
38
+ end
39
+ class Extra < Base
40
+ def code() 2 end
41
+ def expect_data?
42
+ true
43
+ end
44
+ attr_reader :data
45
+ def initialize data
46
+ @data = data
47
+ end
48
+ end
49
+ class Block < Base
50
+ def code() 3 end
51
+ end
52
+ end
53
+
54
+ module Knot::Protocol::Idx
55
+ Idx = [
56
+ :command, # 10, :CMD, # Control command name.
57
+ :flags, # 11, :FLAGS, # Control command flags.
58
+ :error, # 12, :ERROR, # Error message.
59
+ :section, # 13, :SECTION, # Configuration section name.
60
+ :item, # 14, :ITEM, # Configuration item name.
61
+ :id, # 15, :ID, # Congiguration item identifier.
62
+ :zone, # 16, :ZONE, # Zone name.
63
+ :owner, # 17, :OWNER, # Zone record owner
64
+ :ttl, # 18, :TTL, # Zone record TTL.
65
+ :type, # 19, :TYPE, # Zone record type name.
66
+ :data, # 1a, :DATA, # Configuration item/zone record data.
67
+ :filter, # 1b, :FILTER, # An option or a filter for output data processing.
68
+ ]
69
+ Name = {}
70
+ Code = {}
71
+ Idx.each_with_index do |v, i|
72
+ Code[0x10+i] = v
73
+ Name[v] = i
74
+ end
75
+ def self.[] k
76
+ case k
77
+ when Symbol
78
+ Name[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
79
+ when Integer
80
+ Idx[k] or raise Knot::Errors::EINVAL, "Unknown Idx: #{k}"
81
+ else
82
+ raise ArgumentError, "Unknown Idx-Type: #{k}"
83
+ end
84
+ end
85
+ end
86
+
87
+ class Knot::Protocol
88
+ attr_reader :sock, :conf, :zones
89
+ attr_accessor :debug
90
+
91
+ def initialize path_or_sock = nil
92
+ case path_or_sock
93
+ when String, Pathname
94
+ @sock = UNIXSocket.new path_or_sock.to_s
95
+ when Socket
96
+ @sock = path_or_sock
97
+ when nil
98
+ @sock = UNIXSocket.new '/run/knot/knot.sock'
99
+ end
100
+ @debug = false
101
+ @conf = Knot::Conf.new self
102
+ @zones = Hash.new {|h, zone| h[zone] = Knot::Zone.new zone, self }
103
+ end
104
+
105
+ def snd sock: nil, **data
106
+ rsock = sock || @sock
107
+ s = ''
108
+ sock = StringIO.new s
109
+ sock.write [1].pack( 'c')
110
+ data[:flags] ||= ''
111
+ Idx::Idx.each_with_index do |n, i|
112
+ v = data[n]&.to_s
113
+ sock.write [0x10+i, v.size, v].pack( 'c na*') if v
114
+ end
115
+ sock.write [3].pack( 'c')
116
+ sock.flush
117
+ STDERR.puts( {data: data, _: s}.inspect) if @debug
118
+ rsock.write s
119
+ rsock.flush
120
+ end
121
+
122
+ class RecordIO
123
+ attr_reader :str
124
+
125
+ def initialize sock, str = nil
126
+ @str, @sock = str || '', sock
127
+ end
128
+
129
+ def unpack pattern
130
+ IOUnpack.new(pattern).unpack self
131
+ end
132
+
133
+ def unpack1 pattern
134
+ IOUnpack.new(pattern).unpack1 self
135
+ end
136
+
137
+ def read n
138
+ s = @sock.read n
139
+ @str.insert -1, s
140
+ s
141
+ end
142
+ end
143
+
144
+ def rcv sock: nil
145
+ ret, r = [], nil
146
+ sock = sock || @sock
147
+ sock = RecordIO.new sock if @debug
148
+ loop do
149
+ t = sock.unpack1 'c'
150
+ case t
151
+ when 0, 3
152
+ return ret
153
+ when 1, 2
154
+ type = t
155
+ ret.push( r = {})
156
+ else
157
+ raise Knot::Errors::EINVAL, "Missing Type before: #{t}" if ret.empty?
158
+ i = Idx::Idx[t - 0x10] or raise Knot::Errors::EINVAL, "Unknown index: #{t-0x10}"
159
+ l = sock.unpack1 'n'
160
+ r[i] = sock.read( l)
161
+ end
162
+ end
163
+ ensure
164
+ STDERR.puts( {rcvd: ret, read: sock.str}.inspect) if @debug
165
+ ret
166
+ end
167
+
168
+ def call sock: nil, **data
169
+ snd sock: sock, **data
170
+ rcv( sock: sock).each do |r|
171
+ if r[:error]
172
+ if e = Knot::Errors.err2exc[r[:error]]
173
+ raise e, r[:error]
174
+ end
175
+ raise Knot::Error, r[:error]
176
+ end
177
+ end
178
+ end
179
+
180
+ def zone( zone) @zones[zone.to_s.to_sym] end
181
+
182
+ def conf_set( **opts) call opts.update( command: 'conf-set') end
183
+ def conf_unset( **opts) call opts.update( command: 'conf-set') end
184
+
185
+ def zone_set( **opts) call opts.update( command: 'zone-set') end
186
+ def zone_unset( **opts) call opts.update( command: 'zone-unset') end
187
+ def zone_get( **opts) call opts.update( command: 'zone-get') end
188
+ end
@@ -0,0 +1,3 @@
1
+ module Knot
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: knot-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Denis Knauf
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-06-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: iounpack
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Implements knot-protocol to provide an interface to knot-DNS-server
28
+ email:
29
+ - gems+knot@denkn.at
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - ".gitignore"
35
+ - Gemfile
36
+ - LICENSE
37
+ - README.adoc
38
+ - Rakefile
39
+ - knot-ruby.gemspec
40
+ - lib/knot.rb
41
+ - lib/knot/errors.rb
42
+ - lib/knot/interface.rb
43
+ - lib/knot/protocol.rb
44
+ - lib/knot/version.rb
45
+ homepage: https://git.denkn.at/deac/knot
46
+ licenses:
47
+ - LGPL-3.0
48
+ metadata:
49
+ homepage_uri: https://git.denkn.at/deac/knot
50
+ source_code_uri: https://git.denkn.at/deac/knot
51
+ changelog_uri: https://git.denkn.at/deac/knot
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: 2.3.0
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.7.6.2
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: Provides interface to knot-server.
72
+ test_files: []