Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
BIND
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
602
Issues
602
List
Boards
Labels
Service Desk
Milestones
Merge Requests
109
Merge Requests
109
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Packages & Registries
Packages & Registries
Container Registry
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
ISC Open Source Projects
BIND
Commits
dc2a4887
Commit
dc2a4887
authored
May 05, 2016
by
Witold Krecicki
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
4357. [func] Add the python RNDC module. [RT #42093]
parent
08e36aa5
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
205 additions
and
2 deletions
+205
-2
CHANGES
CHANGES
+2
-0
bin/python/isc/Makefile.in
bin/python/isc/Makefile.in
+1
-1
bin/python/isc/__init__.py
bin/python/isc/__init__.py
+2
-1
bin/python/isc/rndc.py
bin/python/isc/rndc.py
+184
-0
bin/tests/system/rndc/tests.sh
bin/tests/system/rndc/tests.sh
+16
-0
No files found.
CHANGES
View file @
dc2a4887
4357. [func] Add the python RNDC module. [RT #42093]
4356. [func] Add the ability to specify whether to wait for
nameserver addresses to be looked up or not to
rpz with a new modifying directive 'nsip-wait-recurse'.
...
...
bin/python/isc/Makefile.in
View file @
dc2a4887
...
...
@@ -23,7 +23,7 @@ SUBDIRS = tests
PYTHON
=
@PYTHON@
PYSRCS
=
__init__.py dnskey.py eventlist.py keydict.py
\
keyevent.py keyzone.py policy.py
keyevent.py keyzone.py policy.py
rndc.py
TARGETS
=
parsetab.py
@BIND9_MAKE_RULES@
...
...
bin/python/isc/__init__.py
View file @
dc2a4887
...
...
@@ -16,7 +16,7 @@
__all__
=
[
'checkds'
,
'coverage'
,
'keymgr'
,
'dnskey'
,
'eventlist'
,
'keydict'
,
'keyevent'
,
'keyseries'
,
'keyzone'
,
'policy'
,
'parsetab'
,
'utils'
]
'parsetab'
,
'
rndc'
,
'
utils'
]
from
isc.dnskey
import
*
from
isc.eventlist
import
*
...
...
@@ -25,4 +25,5 @@ from isc.keyevent import *
from
isc.keyseries
import
*
from
isc.keyzone
import
*
from
isc.policy
import
*
from
isc.rndc
import
*
from
isc.utils
import
*
bin/python/isc/rndc.py
0 → 100644
View file @
dc2a4887
############################################################################
# Copyright (C) 2016 Internet Systems Consortium, Inc. ("ISC")
#
# Permission to use, copy, modify, and/or distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
############################################################################
############################################################################
# rndc.py
# This module implements the RNDC control protocol.
############################################################################
from
collections
import
OrderedDict
from
exceptions
import
TypeError
import
time
import
struct
import
hashlib
import
hmac
import
base64
import
random
import
socket
class
rndc
(
object
):
"""RNDC protocol client library"""
__algos
=
{
'md5'
:
157
,
'sha1'
:
161
,
'sha224'
:
162
,
'sha256'
:
163
,
'sha384'
:
164
,
'sha512'
:
165
}
def
__init__
(
self
,
host
,
algo
,
secret
):
"""Creates a persistent connection to RNDC and logs in
host - (ip, port) tuple
algo - HMAC algorithm: one of md5, sha1, sha224, sha256, sha384, sha512
(with optional prefix 'hmac-')
secret - HMAC secret, base64 encoded"""
self
.
host
=
host
algo
=
algo
.
lower
()
if
algo
.
startswith
(
'hmac-'
):
algo
=
algo
[
5
:]
self
.
algo
=
algo
self
.
hlalgo
=
getattr
(
hashlib
,
algo
)
self
.
secret
=
base64
.
b64decode
(
secret
)
self
.
ser
=
random
.
randint
(
0
,
1
<<
24
)
self
.
nonce
=
None
self
.
__connect_login
()
def
call
(
self
,
cmd
):
"""Call a RNDC command, all parsing is done on the server side
cmd - a complete string with a command (eg 'reload zone example.com')
"""
return
dict
(
self
.
__command
(
type
=
cmd
)[
'_data'
])
def
__serialize_dict
(
self
,
data
,
ignore_auth
=
False
):
rv
=
''
for
k
,
v
in
data
.
iteritems
():
if
ignore_auth
and
k
==
'_auth'
:
continue
rv
+=
chr
(
len
(
k
))
rv
+=
k
if
type
(
v
)
==
str
:
rv
+=
struct
.
pack
(
'>BI'
,
1
,
len
(
v
))
+
v
elif
type
(
v
)
==
OrderedDict
:
sd
=
self
.
__serialize_dict
(
v
)
rv
+=
struct
.
pack
(
'>BI'
,
2
,
len
(
sd
))
+
sd
else
:
raise
NotImplementedError
(
'Cannot serialize element of type %s'
%
type
(
v
))
return
rv
def
__prep_message
(
self
,
*
args
,
**
kwargs
):
self
.
ser
+=
1
now
=
int
(
time
.
time
())
data
=
OrderedDict
(
*
args
,
**
kwargs
)
d
=
OrderedDict
()
d
[
'_auth'
]
=
OrderedDict
()
d
[
'_ctrl'
]
=
OrderedDict
()
d
[
'_ctrl'
][
'_ser'
]
=
str
(
self
.
ser
)
d
[
'_ctrl'
][
'_tim'
]
=
str
(
now
)
d
[
'_ctrl'
][
'_exp'
]
=
str
(
now
+
60
)
if
self
.
nonce
is
not
None
:
d
[
'_ctrl'
][
'_nonce'
]
=
self
.
nonce
d
[
'_data'
]
=
data
msg
=
self
.
__serialize_dict
(
d
,
ignore_auth
=
True
)
hash
=
hmac
.
new
(
self
.
secret
,
msg
,
self
.
hlalgo
).
digest
()
bhash
=
base64
.
b64encode
(
hash
)
if
self
.
algo
==
'md5'
:
d
[
'_auth'
][
'hmd5'
]
=
struct
.
pack
(
'22s'
,
bhash
)
else
:
d
[
'_auth'
][
'hsha'
]
=
struct
.
pack
(
'B88s'
,
self
.
__algos
[
self
.
algo
],
bhash
)
msg
=
self
.
__serialize_dict
(
d
)
msg
=
struct
.
pack
(
'>II'
,
len
(
msg
)
+
4
,
1
)
+
msg
return
msg
def
__verify_msg
(
self
,
msg
):
if
self
.
nonce
is
not
None
and
msg
[
'_ctrl'
][
'_nonce'
]
!=
self
.
nonce
:
return
False
bhash
=
msg
[
'_auth'
][
'hmd5'
if
self
.
algo
==
'md5'
else
'hsha'
]
bhash
+=
'='
*
(
4
-
(
len
(
bhash
)
%
4
))
remote_hash
=
base64
.
b64decode
(
bhash
)
my_msg
=
self
.
__serialize_dict
(
msg
,
ignore_auth
=
True
)
my_hash
=
hmac
.
new
(
self
.
secret
,
my_msg
,
self
.
hlalgo
).
digest
()
return
(
my_hash
==
remote_hash
)
def
__command
(
self
,
*
args
,
**
kwargs
):
msg
=
self
.
__prep_message
(
*
args
,
**
kwargs
)
sent
=
self
.
socket
.
send
(
msg
)
if
sent
!=
len
(
msg
):
raise
IOError
(
"Cannot send the message"
)
header
=
self
.
socket
.
recv
(
8
)
if
len
(
header
)
!=
8
:
# What should we throw here? Bad auth can cause this...
raise
IOError
(
"Can't read response header"
)
length
,
version
=
struct
.
unpack
(
'>II'
,
header
)
if
version
!=
1
:
raise
NotImplementedError
(
'Wrong message version %d'
%
version
)
# it includes the header
length
-=
4
data
=
self
.
socket
.
recv
(
length
,
socket
.
MSG_WAITALL
)
if
len
(
data
)
!=
length
:
raise
IOError
(
"Can't read response data"
)
msg
=
self
.
__parse_message
(
data
)
if
not
self
.
__verify_msg
(
msg
):
raise
IOError
(
"Authentication failure"
)
return
msg
def
__connect_login
(
self
):
self
.
socket
=
socket
.
create_connection
(
self
.
host
)
self
.
nonce
=
None
msg
=
self
.
__command
(
type
=
'null'
)
self
.
nonce
=
msg
[
'_ctrl'
][
'_nonce'
]
def
__parse_element
(
self
,
input
):
pos
=
0
labellen
=
ord
(
input
[
pos
])
pos
+=
1
label
=
input
[
pos
:
pos
+
labellen
]
pos
+=
labellen
type
=
ord
(
input
[
pos
])
pos
+=
1
datalen
=
struct
.
unpack
(
'>I'
,
input
[
pos
:
pos
+
4
])[
0
]
pos
+=
4
data
=
input
[
pos
:
pos
+
datalen
]
pos
+=
datalen
rest
=
input
[
pos
:]
if
type
==
1
:
# raw binary value
return
label
,
data
,
rest
elif
type
==
2
:
# dictionary
d
=
OrderedDict
()
while
len
(
data
)
>
0
:
ilabel
,
value
,
data
=
self
.
__parse_element
(
data
)
d
[
ilabel
]
=
value
return
label
,
d
,
rest
# TODO type 3 - list
else
:
raise
NotImplementedError
(
'Unknown element type %d'
%
type
)
def
__parse_message
(
self
,
input
):
rv
=
OrderedDict
()
hdata
=
None
while
len
(
input
)
>
0
:
label
,
value
,
input
=
self
.
__parse_element
(
input
)
rv
[
label
]
=
value
return
rv
bin/tests/system/rndc/tests.sh
View file @
dc2a4887
...
...
@@ -448,4 +448,20 @@ grep "^running on " rndc.output > /dev/null || ret=1
if
[
$ret
!=
0
]
;
then
echo
"I:failed"
;
fi
status
=
`
expr
$status
+
$ret
`
if
[
-x
"
$PYTHON
"
]
;
then
echo
"I:test rndc python bindings"
ret
=
0
$PYTHON
>
rndc.output
<<
EOF
import sys
sys.path.insert(0, '../../../../bin/python')
from isc import *
r = rndc(('10.53.0.5', 9953), 'hmac-sha256', '1234abcd8765')
result = r.call('status')
print(result['text'])
EOF
grep
'server is up and running'
rndc.output
>
/dev/null 2>&1
||
ret
=
1
if
[
$ret
!=
0
]
;
then
echo
"I:failed"
;
fi
status
=
`
expr
$status
+
$ret
`
fi
exit
$status
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment