œ_#ÁÕ§TE NAŒ“KeÉ:”(åŽÖJÞùY’‚ñùž7; «]Û ý`8g“¯B© jdÖÖ¸ðzœ¸¦4Ç3Kó^(ÍÖ¼ Õ€pvìwšõB4df$Èü^0˜…åÌC$#2FŽÑ§±¦ÛZ/÷š&m£ñzÒÖ ’.Î]!Î;ƒ(Õ–¢d/—#Kª+tZyuÏB>NÛÖ†(¸ŒSà'³„Y˜´-_•¦¼´˜OlNK§¶ÒàŠˆTHµƒeTPå·fïM’…þuÏÍüp6دªE£åü‡ZØ'CKF#â«;‹eyO Qp„†l"ö1èíÙP ÏŒúl! BÝ2ñª•_VÁÉ÷3eu`–F¸ìI--ö<¿žë¯4õ캿¢)34Å{wMÉ2ÆÖFŸ¥`e9Ú¶¸P‡.”FÔï rY ‚²ÈTB,{ÛœéJ}«àQ4¹0Rû4D‚B§S‘ dO•v¾„™Sן¯3FeŸ™«+ÓâwH dÕÛÌì·P4ë&¥#rÜÉ Ù¦ê†ý·xòqk¯2,¹§™E\ék‚×Sá”ÚºÙ⺷ö£6…à ʾ qSá³Å|;àû}4Ÿ($â¹VY~óÍ!èÜÒŒËX½Ù1j‚VíÍŸš³+œ]«½g{_{/vµ½\¢¶vÉWKÿ:ñám½ ¥ S²x‘t ŽšÝÙÿÀÇ^ný PK IW™k‚½÷ á _rels/.relsUT dìd dìd dìd’ÏNÃ0‡ï{ŠÈ÷ÕÝ@¡¥» ¤Ý*`%îÑ&QâÁöö‚J£ì°cœŸ¿|¶²ÙÆA½rL½wVE Šñ¶w†çúay * 9Kƒw¬áÈ ¶ÕbóÄIîI]’Ê—4t"á1™ŽGJ…ìòMããH’±Å@æ…ZÆuYÞ`üÍ€jÂT;«!îì T}|Û7MoøÞ›ýÈNN<|v–í2ÄÜ¥ÏèšbË¢Ázó˜Ë )„"£OÏ7ú{ZYÈ’yÞç#1'tuÉM?6o>Z´_å9›ëKÚ˜}?þ³žÏÌ·N>fµx PK IWª½e ¢ U € word/document.xmlUT dìdPK IWþË3” z €J¢ word/settings.xmlUT dìdPK IWC‡{š' ƒ €¤ docProps/custom.xmlUT dìdPK IW츱=Œ €‡¥ [Content_Types].xmlUT dìdPK IWV%ë±" €U§ docProps/app.xmlUT dìdPK IW€RŒ 3 €¶¨ docProps/core.xmlUT dìdPK IWkòDn ô €ª word/_rels/document.xml.relsUT dìdPK IW;$î €Î« word/fontTable.xmlUT dìdPK IW+åäz] ÷. €ý¬ word/numbering.xmlUT dìdPK IW¤2×r- ¿ €›° word/styles.xmlUT dìdPK IWMFÒ ø €´ word/header1.xmlUT dìdPK IWF— T e €· word/media/image1.jpegUT dìdPK IW!Yéáå €°Ë word/media/image2.pngUT dìdPK IW°Àºë ú €ÙÌ word/media/image3.pngUT dìdPK IW$“†ª L €Î word/footer1.xmlUT dìdPK IWzaGôM €ñÑ word/footer2.xmlUT dìdPK IW–µâº P €}Õ word/theme/theme1.xmlUT dìdPK IW™k‚½÷ á €{Û _rels/.relsUT PK ! bîh^ [Content_Types].xml ¢( ¬”ËNÃ0E÷HüCä-Jܲ@5í‚Ç*Q>Àēƪc[žiiÿž‰ûB¡j7±ÏÜ{2ñÍh²nm¶‚ˆÆ»R‹ÈÀU^7/ÅÇì%¿’rZYï @1__f› ˜q·ÃR4DáAJ¬h>€ãÚÇV߯¹ªZ¨9ÈÛÁàNVÞ8Ê©ÓãÑÔji){^óã-I‹"{Üv^¥P!XS)bR¹rú—K¾s(¸3Õ`cÞ0†½ÝÎß»¾7M4²©ŠôªZÆk+¿|\|z¿(Ž‹ôPúº6h_-[ž@!‚ÒØ Pk‹´2nÏ}Ä?£LËð Ýû%áÄßdºždN"m,à¥ÇžDO97*‚~§Èɸ8ÀOíc|n¦Ñ äEøÿöéºóÀBÉÀ!$}‡íàÈé;{ìÐå[ƒîñ–é2þ ÿÿ PK ! µU0#ô L _rels/.rels ¢( ¬’MOÃ0†ïHü‡È÷ÕÝBKwAH»!T~€Iܵ£$Ý¿'TƒG½~üÊÛÝ<êÈ!öâ4¬‹;#¶w†—úqu *&r–Fq¬áÄvÕõÕö™GJy(v½*«¸¨¡KÉß#FÓñD±Ï.W ¥†=™ZÆMYÞbø®ÕBS톰·7 ê“Ï›×–¦é ?ˆ9LìÒ™ÈsbgÙ®|Èl!õùUSh9i°bžr:"y_dlÀóD›¿ý|-NœÈR"4ø2ÏGÇ% õZ´4ñËyÄ7 ëÈðÉ‚‹¨Þ ÿÿ PK ! Q48wÛ — xl/workbook.xml¤UÙnâ0}iþ!cñ‡ *–¢AšVU×$dC¬&vÆv UÕŸë@XÊK§/¹p|Žï¹N÷b“¥Ö •Š ÞC¸î"‹òHÄŒ¯zèá~b·‘¥4á1I§=ôJºèÿüÑ] ù¼âÙ ®z(Ñ:GE ͈ª‹œrˆ,…̈†©\9*—”Ä*¡Tg©ã¹nàd„q´Eåg0ÄrÉ":Q‘Q®· ’¦D}•°\UhYô¸ŒÈç"·#‘å ±`)Ó¯%(²²(œ®¸d‘‚ì nZ w v¡ñª• t¶TÆ")”Xê:@;[Ògú±ë`|²›ó=ø’ïHúÂL÷¬dðEVÁ+8€a÷Ûh¬Uz%„Íû"ZsÏÍCýî’¥ôqk]‹äù5ÉL¦Rd¥Dé˘i÷P ¦bM/|dÉ",…¨çãFNoçiûéë>aêiçsó#ðÄ ÕTr¢éHp ÜIú®ÝJìQ"ÀÜÖ-ý[0I¡¦ÀZ Z…d¡nˆN¬B¦=4 g %PDF-1.4 %âãÏÓ 3 0 obj << /Linearized 1 /L 422775 ÿØÿà JFIF ÿÛ C ÿÛ C ÿÀ X" ÿÄ ÿÄ H !1A"Qaq2‘¡#±ÁBRÑ3Cbrá$S‚¢²ð4ñ%6DTc’ÂsÿÄ ÿÄ = !1AQ"aq‘Á2R¡±BÑð#3br’²4á$‚¢ÂñÿÚ ? áHBßÝ`„! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! !@B„ „! ! stream
############################################################################
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
#
# See the COPYRIGHT file distributed with this work for additional
# information regarding copyright ownership.
############################################################################
############################################################################
# rndc.py
# This module implements the RNDC control protocol.
############################################################################
from collections import OrderedDict
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 = bytearray()
for k, v in data.items():
if ignore_auth and k == '_auth':
continue
rv += struct.pack('B', len(k)) + k.encode('ascii')
if type(v) == str:
rv += struct.pack('>BI', 1, len(v)) + v.encode('ascii')
elif type(v) == bytes:
rv += struct.pack('>BI', 1, len(v)) + v
elif type(v) == bytearray:
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'] = bytearray(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
if self.algo == 'md5':
bhash = msg['_auth']['hmd5']
else:
bhash = msg['_auth']['hsha'][1:]
if type(bhash) == bytes:
bhash = bhash.decode('ascii')
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")
if type(data) == str:
data = bytearray(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 = input[pos]
pos += 1
label = input[pos:pos+labellen].decode('ascii')
pos += labellen
type = 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