def process(self): """ Start listening and processing Queries. :return: """ # TODO: need to figure out what to do when ony IPv4 address is to be used s_udp6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s_tcp6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s_udp6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s_tcp6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._sockets.append(s_udp6) self._sockets.append(s_tcp6) try: # kernel allows to receive IPv4 packets try: s_udp6.bind((self._listen_address, self._listen_port)) s_tcp6.bind((self._listen_address, self._listen_port)) except socket.error as e: # [Errno 13] Permission denied if e.errno == 13: logger.error('You need to be root to bind to port %s', str(self._listen_port)) # [Errno -9] Address family for hostname not supported elif e.errno == -9: logger.error( "Only IPv4 addresses or 'localhost' is supported at this point." ) raise BrokenDNSProxyError(e.strerror) s_tcp6.listen(0) logger.info('Listening on port %s...', str(self._listen_port)) while True: ready_r, ready_w, _ = select.select(self._sockets, [], []) for s in ready_r: client = Client(s) msg = client.msg() # sample code sending a response to the client upstream_server = random.choice(self._upstream_servers) logger.debug("Forwarding Query to upstream server '%s'", str(upstream_server)) response = dns.query.udp(msg, upstream_server) # modify the message for client self._modification_chain.run_modifiers(response) client.send(response) finally: for s in self._sockets: s.close()
def _handle_datagram_socket(self, server_socket): """ :param server_socket: :return: """ # 16bit max udp length limit self._client_msg_raw, self._client_addr = server_socket.recvfrom(2**16) logger.debug('Received UDP data from: %s', str(self._client_addr)) self._client_msg_len = len(self._client_msg_raw) logger.debug('UDP Query of length %s', str(self._client_msg_len)) self._client_sock = server_socket
def run_modifiers(self, dns_message): """ :param dns_message: :return: """ logger.debug("Running total '%d' modifiers...", len(self._modifiers)) for mod in self._modifiers: logger.debug("Running '%s' modifier...", mod.config_section_name()) dns_message = mod.modify(dns_message) return dns_message
def process(self): """ Start listening and processing Queries. :return: """ # TODO: need to figure out what to do when ony IPv4 address is to be used s_udp6 = socket.socket(socket.AF_INET6, socket.SOCK_DGRAM) s_tcp6 = socket.socket(socket.AF_INET6, socket.SOCK_STREAM) s_udp6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) s_tcp6.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._sockets.append(s_udp6) self._sockets.append(s_tcp6) try: # kernel allows to receive IPv4 packets try: s_udp6.bind((self._listen_address, self._listen_port)) s_tcp6.bind((self._listen_address, self._listen_port)) except socket.error as e: # [Errno 13] Permission denied if e.errno == 13: logger.error('You need to be root to bind to port %s', str(self._listen_port)) # [Errno -9] Address family for hostname not supported elif e.errno == -9: logger.error("Only IPv4 addresses or 'localhost' is supported at this point.") raise BrokenDNSProxyError(e.strerror) s_tcp6.listen(0) logger.info('Listening on port %s...', str(self._listen_port)) while True: ready_r, ready_w, _ = select.select(self._sockets, [], []) for s in ready_r: client = Client(s) msg = client.msg() # sample code sending a response to the client upstream_server = random.choice(self._upstream_servers) logger.debug("Forwarding Query to upstream server '%s'", str(upstream_server)) response = dns.query.udp(msg, upstream_server) # modify the message for client self._modification_chain.run_modifiers(response) client.send(response) finally: for s in self._sockets: s.close()
def __init__(self, configuration): """ :param configuration: :return: """ self._modifiers = list() modifiers_list = configuration.getlist(GlobalConfig.config_section_name(), GlobalConfig.CONFIG_MODIFIERS) for mod_name in modifiers_list: mod = get_modifier_by_name(mod_name) if not mod: raise BrokenDNSProxyError("Modifier '{0}' does not exist!".format(mod_name)) logger.debug("Adding modifier '%s' to Modification Chain", mod_name) self._modifiers.append(mod(configuration))
def __init__(self, server_socket): """ Constructor :param server_socket: The socket object on which we have possible client pending :return: None """ if server_socket.type not in (socket.SOCK_DGRAM, socket.SOCK_STREAM): raise BrokenDNSProxyError("Pending client on socket with wrong type '{0}'".format(server_socket.type)) self._receive_client_msg(server_socket) self._client_msg = dns.message.from_wire(self._client_msg_raw) logger.debug("Received DNS message:\n" "-----------------------------\n" "%s\n" "-----------------------------", str(self._client_msg))
def __init__(self, cli_conf): self._config = ConfigParser() self._add_commandline_arguments(cli_conf) self._read_proxy_default_config() config_abs_path = os.path.abspath(cli_conf.config_path) try: self._config.read(config_abs_path)[0] except IndexError: logger.warning("Configuration file '%s' could not be read... " "Using ONLY default settings", config_abs_path) else: logger.debug("Using configuration from '%s'", config_abs_path) # include configuration for all modifiers self._read_modifiers_default_config()
def send(self, msg): """ Send the msg as a response to the client query. :param msg: DNS Message object :return: None """ logger.debug( 'Sending message to client %s:\n' '-----------------------------\n' '%s\n' '-----------------------------', str(self._client_addr), str(msg)) if self._client_sock.type == socket.SOCK_STREAM: self._send_stream(msg) elif self._client_sock.type == socket.SOCK_DGRAM: self._send_datagram(msg)
def send(self, msg): """ Send the msg as a response to the client query. :param msg: DNS Message object :return: None """ logger.debug('Sending message to client %s:\n' '-----------------------------\n' '%s\n' '-----------------------------', str(self._client_addr), str(msg)) if self._client_sock.type == socket.SOCK_STREAM: self._send_stream(msg) elif self._client_sock.type == socket.SOCK_DGRAM: self._send_datagram(msg)
def __init__(self, cli_conf): self._config = ConfigParser() self._add_commandline_arguments(cli_conf) self._read_proxy_default_config() config_abs_path = os.path.abspath(cli_conf.config_path) try: self._config.read(config_abs_path)[0] except IndexError: logger.warning( "Configuration file '%s' could not be read... " "Using ONLY default settings", config_abs_path) else: logger.debug("Using configuration from '%s'", config_abs_path) # include configuration for all modifiers self._read_modifiers_default_config()
def __init__(self, configuration): """ :param configuration: :return: """ self._modifiers = list() modifiers_list = configuration.getlist( GlobalConfig.config_section_name(), GlobalConfig.CONFIG_MODIFIERS) for mod_name in modifiers_list: mod = get_modifier_by_name(mod_name) if not mod: raise BrokenDNSProxyError( "Modifier '{0}' does not exist!".format(mod_name)) logger.debug("Adding modifier '%s' to Modification Chain", mod_name) self._modifiers.append(mod(configuration))
def _handle_stream_socket(self, server_socket): """ :param server_socket: :return: """ self._client_sock, self._client_addr = server_socket.accept() logger.debug('TCP client %s connected', str(self._client_addr)) self._client_msg_len = struct.unpack('!H', self._client_sock.recv(2))[0] logger.debug('TCP Query of length %s', str(self._client_msg_len)) while len(self._client_msg_raw) < self._client_msg_len: # read all data chunk = self._client_sock.recv(self._client_msg_len - len(self._client_msg_raw)) if not chunk: raise BrokenDNSProxyError('Unable to get all TCP data') self._client_msg_raw += chunk
def __init__(self, server_socket): """ Constructor :param server_socket: The socket object on which we have possible client pending :return: None """ if server_socket.type not in (socket.SOCK_DGRAM, socket.SOCK_STREAM): raise BrokenDNSProxyError( "Pending client on socket with wrong type '{0}'".format( server_socket.type)) self._receive_client_msg(server_socket) self._client_msg = dns.message.from_wire(self._client_msg_raw) logger.debug( "Received DNS message:\n" "-----------------------------\n" "%s\n" "-----------------------------", str(self._client_msg))
def run(self): logger.debug("Staring proxy server '%s'", str(self._server)) self._server.process()
def modify(self, dns_message): """ Method modifying the DNS message, based on Modifier configuration :param dns_message: dns message object to modify :return: possibly modified dns message object """ # go through all flags in settings and set/clear/do nothing with the flag # AA Authoritative Answer [RFC 1035] if self._aa_flag is not None: if self._aa_flag: logger.debug("Setting AA flag") dns_message.flags |= dns.flags.AA else: logger.debug("Clearing AA flag") dns_message.flags &= ~dns.flags.AA # TC Truncated Response [RFC 1035] if self._tc_flag is not None: if self._tc_flag: logger.debug("Setting TC flag") dns_message.flags |= dns.flags.TC else: logger.debug("Clearing TC flag") dns_message.flags &= ~dns.flags.TC # RD Recursion Desired [RFC 1035] if self._rd_flag is not None: if self._rd_flag: logger.debug("Setting RD flag") dns_message.flags |= dns.flags.RD else: logger.debug("Clearing RD flag") dns_message.flags &= ~dns.flags.RD # RA Recursion Allowed [RFC 1035] if self._ra_flag is not None: if self._ra_flag: logger.debug("Setting RA flag") dns_message.flags |= dns.flags.RA else: logger.debug("Clearing RA flag") dns_message.flags &= ~dns.flags.RA # AD Authentic Data [RFC 4035] if self._ad_flag is not None: if self._ad_flag: logger.debug("Setting AD flag") dns_message.flags |= dns.flags.AD else: logger.debug("Clearing AD flag") dns_message.flags &= ~dns.flags.AD # CD Checking Disabled [RFC 4035] if self._cd_flag is not None: if self._cd_flag: logger.debug("Setting CD flag") dns_message.flags |= dns.flags.CD else: logger.debug("Clearing CD flag") dns_message.flags &= ~dns.flags.CD # DO DNSSEC answer OK [RFC 4035][RFC 3225] if self._do_flag is not None: if self._do_flag: # enable EDNS if not enabled if dns_message.edns == -1: logger.debug("EDNS0 not used... enabling") dns.message.use_edns() logger.debug("Setting DO flag") dns_message.ednsflags |= dns.flags.DO else: logger.debug("Clearing DO flag") dns_message.ednsflags &= ~dns.flags.DO