knot-ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +154 -0
- data/Gemfile +6 -0
- data/LICENSE +163 -0
- data/README.adoc +46 -0
- data/Rakefile +2 -0
- data/knot-ruby.gemspec +31 -0
- data/lib/knot.rb +4 -0
- data/lib/knot/errors.rb +166 -0
- data/lib/knot/interface.rb +159 -0
- data/lib/knot/protocol.rb +188 -0
- data/lib/knot/version.rb +3 -0
- metadata +72 -0
checksums.yaml
ADDED
@@ -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
|
data/.gitignore
ADDED
@@ -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
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.
|
data/README.adoc
ADDED
@@ -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.
|
data/Rakefile
ADDED
data/knot-ruby.gemspec
ADDED
@@ -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
|
data/lib/knot.rb
ADDED
data/lib/knot/errors.rb
ADDED
@@ -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
|
data/lib/knot/version.rb
ADDED
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: []
|