Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
ISC Open Source Projects
BIND
Commits
dc2a4887
Commit
dc2a4887
authored
May 05, 2016
by
Witold Krecicki
Browse files
4357. [func] Add the python RNDC module. [RT #42093]
parent
08e36aa5
Changes
5
Hide whitespace changes
Inline
Side-by-side
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
Supports
Markdown
0%
Try again
or
attach a new 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