def getnameinfo(self, ip_port, flags, callback): if not callable(callback): raise AresError("a callable is required") ip, port = ip_port if port < 0 or port > 65535: raise ValueError("port must be between 0 and 65535") sa4 = _ffi.new("struct sockaddr_in*") sa6 = _ffi.new("struct sockaddr_in6*") if 1 == _lib.ares_inet_pton(socket.AF_INET, s2b(ip), _ffi.addressof(sa4.sin_addr)): sa4.sin_family = socket.AF_INET sa4.sin_port = socket.htons(port) sa = sa4 elif 1 == _lib.ares_inet_pton(socket.AF_INET6, s2b(ip), _ffi.addressof(sa6.sin6_addr)): sa6.sin6_family = socket.AF_INET6 sa6.sin6_port = socket.htons(port) sa = sa6 else: raise ValueError("invalid IP address") userdata = _ffi.new_handle(callback) _global_set.add(userdata) _lib.ares_getnameinfo(self.channel, _ffi.cast("struct sockaddr*", sa), _ffi.sizeof(sa[0]), flags, _nameinfo_cb, userdata)
def set_local_ip(self, ip): addr4 = _ffi.new("struct in_addr*") addr6 = _ffi.new("struct ares_in6_addr*") if 1 == _lib.ares_inet_pton(socket.AF_INET, s2b(ip), addr4): _lib.ares_set_local_ip4(self.channel, socket.ntohl(addr4.s_addr)) elif 1 == _lib.ares_inet_pton(socket.AF_INET6, s2b(ip), addr6): _lib.ares_set_local_ip6(self.channel, addr6) else: raise ValueError("invalid IP address")
def timeout(self, t = -1): maxtv = _ffi.NULL tv = _ffi.new("struct timeval*") if t >= 0.0: maxtv = _ffi.new("struct timeval*") maxtv.tv_sec = int(math.floor(t)) maxtv.tv_usec = int(math.fmod(t, 1.0) * 1000000) elif t == -1: pass else: raise ValueError("timeout needs to be a positive number") _lib.ares_timeout(self.channel, maxtv, tv) return (tv.tv_sec + tv.tv_usec / 1000000.0)
def gethostbyaddr(self, name, callback): if not callable(callback): raise TypeError("a callable is required") addr4 = _ffi.new("struct in_addr*") addr6 = _ffi.new("struct ares_in6_addr*") if 1 == _lib.ares_inet_pton(socket.AF_INET,s2b(name), (addr4)): address = addr4 family = socket.AF_INET elif 1 == _lib.ares_inet_pton(socket.AF_INET6, s2b(name), (addr6)): address = addr6 family = socket.AF_INET6 else: raise ValueError("invalid IP address") userdata = _ffi.new_handle(callback) _global_set.add(userdata) _lib.ares_gethostbyaddr(self.channel, (address), _ffi.sizeof(address[0]), family, _host_cb, userdata)
def __init__(self, ares_addrttl): buf = _ffi.new("char[]", _lib.INET6_ADDRSTRLEN) if _ffi.typeof(ares_addrttl) is _ffi.typeof("struct ares_addrttl"): _lib.ares_inet_ntop(socket.AF_INET, _ffi.addressof(ares_addrttl.ipaddr), buf, _lib.INET6_ADDRSTRLEN) elif _ffi.typeof(ares_addrttl) is _ffi.typeof("struct ares_addr6ttl"): _lib.ares_inet_ntop(socket.AF_INET6, _ffi.addressof(ares_addrttl.ip6addr), buf, _lib.INET6_ADDRSTRLEN) else: raise TypeError() self.host = _ffi_string(buf, _lib.INET6_ADDRSTRLEN) self.ttl = ares_addrttl.ttl
def _get_servers(self): servers = _ffi.new("struct ares_addr_node **") r = _lib.ares_get_servers(self.channel, servers) if r != ARES_SUCCESS: raise AresError(errno.strerror(r)) server_list = [] server = _ffi.new("struct ares_addr_node **", servers[0]) while True: if server == _ffi.NULL: break ip = _ffi.new("char []", _lib.INET6_ADDRSTRLEN) if _ffi.NULL != _lib.ares_inet_ntop(server.family, _ffi.addressof(server.addr), ip, _lib.INET6_ADDRSTRLEN): server_list.append(_ffi_string(ip, _lib.INET6_ADDRSTRLEN)) server = server.next return server_list
def getsock(self): rfds = [] wfds = [] socks = _ffi.new("ares_socket_t [%d]" % _lib.ARES_GETSOCK_MAXNUM) bitmask = _lib.ares_getsock(self.channel, socks, _lib.ARES_GETSOCK_MAXNUM) for i in range(_lib.ARES_GETSOCK_MAXNUM): if bitmask & (1 << i): rfds.append(socks[i]) if bitmask & (1 << (i + _lib.ARES_GETSOCK_MAXNUM)): wfds.append(socks[i]) return rfds, wfds
def __init__(self, hostent): self.name = _ffi_string(hostent.h_name) self.aliases = [] self.addresses = [] for i in range(100): if hostent.h_aliases[i] == _ffi.NULL: break self.aliases.append(_ffi_string(hostent.h_aliases[i])) for i in range(100): if hostent.h_addr_list[i] == _ffi.NULL: break buf = _ffi.new("char[]", _lib.INET6_ADDRSTRLEN) if _ffi.NULL != _lib.ares_inet_ntop(hostent.h_addrtype, hostent.h_addr_list[i], buf, _lib.INET6_ADDRSTRLEN): self.addresses.append(_ffi_string(buf, _lib.INET6_ADDRSTRLEN))
def _set_servers(self, servers): c = _ffi.new("struct ares_addr_node[%d]" % len(servers)) for i in range(len(servers)): if 1 == _lib.ares_inet_pton(socket.AF_INET, s2b(servers[i]), _ffi.addressof(c[i].addr.addr4)): c[i].family = socket.AF_INET elif 1 == _lib.ares_inet_pton(socket.AF_INET6, s2b(servers[i]), _ffi.addressof(c[i].addr.addr6)): c[i].family = socket.AF_INET6 else: raise ValueError("invalid IP address") if i > 0: c[i - 1].next = _ffi.addressof(c[i]) r = _lib.ares_set_servers(self.channel, c) if r != _lib.ARES_SUCCESS: raise AresError()
def reverse_address(ip): """Get reverse representation of an IP address""" name = _ffi.new("char []", 128) if _ffi.NULL == _lib.reverse_address(s2b(ip), name): raise ValueError("invalid IP address") return _ffi_string(name, 128)
def __init__(self, flags = -1, timeout = -1.0, tries = -1, ndots = -1, tcp_port = -1, udp_port = -1, servers = None, domains = None, lookups = None, sock_state_cb = None, socket_send_buffer_size = -1, socket_receive_buffer_size = -1, rotate = False): channel = _ffi.new("ares_channel *") options = _ffi.new("struct ares_options *") optmask = 0 if flags != -1: options.flags = flags optmask = optmask | _lib.ARES_OPT_FLAGS if timeout != -1: options.timeout = int(timeout * 1000) optmask = optmask | _lib.ARES_OPT_TIMEOUTMS if tries != -1: options.tries = tries optmask = optmask | _lib.ARES_OPT_TRIES if ndots != -1: options.ndots = ndots optmask = optmask | _lib.ARES_OPT_NDOTS if tcp_port != -1: options.tcp_port = tcp_port optmask = optmask | _lib.ARES_OPT_TCP_PORT if udp_port != -1: options.udp_port = udp_port optmask = optmask | _lib.ARES_OPT_UDP_PORT if socket_send_buffer_size != -1: options.socket_send_buffer_size = socket_send_buffer_size optmask = optmask | _lib.ARES_OPT_SOCK_SNDBUF if socket_receive_buffer_size != -1: options.socket_receive_buffer_size = socket_receive_buffer_size optmask = optmask | _lib.ARES_OPT_SOCK_RCVBUF if sock_state_cb: if not callable(sock_state_cb): raise AresError("sock_state_cb is not callable") userdata = _ffi.new_handle(sock_state_cb) _global_set.add(userdata) # must keep this alive! options.sock_state_cb = _sock_state_cb options.sock_state_cb_data = userdata optmask = optmask | _lib.ARES_OPT_SOCK_STATE_CB if lookups: options.lookups = lookups optmask = optmask | _lib.ARES_OPT_LOOKUPS if domains: strs = [_ffi.new("char[]", s2b(i)) for i in domains] c = _ffi.new("char *[%d]" % (len(domains) + 1)) for i in range(len(domains)): c[i] = strs[i] options.domains = c options.ndomains = len(domains) optmask = optmask | _lib.ARES_OPT_DOMAINS if rotate == True: optmask = optmask | _lib.ARES_OPT_ROTATE r = _lib.ares_init_options(channel, options, optmask) if r != _lib.ARES_SUCCESS: raise AresError() self.channel = channel[0] if servers: self._set_servers(servers)
def _query_cb(arg, status, timeouts, abuf, alen): result = None callback, query_type = _ffi.from_handle(arg) if status == _lib.ARES_SUCCESS: if query_type == _lib.T_A: addrttls = _ffi.new("struct ares_addrttl[]", PYCARES_ADDRTTL_SIZE) naddrttls = _ffi.new("int*", PYCARES_ADDRTTL_SIZE) parse_status = _lib.ares_parse_a_reply(abuf, alen, _ffi.NULL, addrttls, naddrttls) if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [ares_query_simple_result(addrttls[i]) for i in range(naddrttls[0])] status = None elif query_type == _lib.T_AAAA: addrttls = _ffi.new("struct ares_addr6ttl[]", PYCARES_ADDRTTL_SIZE) naddrttls = _ffi.new("int*", PYCARES_ADDRTTL_SIZE) parse_status = _lib.ares_parse_aaaa_reply(abuf, alen, _ffi.NULL, addrttls, naddrttls) if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [ares_query_simple_result(addrttls[i]) for i in range(naddrttls[0])] status = None elif query_type == _lib.T_CNAME: host = _ffi.new("struct hostent **") parse_status = _lib.ares_parse_a_reply(abuf, alen, host, _ffi.NULL, _ffi.NULL) if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = ares_query_cname_result(host[0]) _lib.ares_free_hostent(host[0]) status = None elif query_type == _lib.T_MX: mx_reply = _ffi.new("struct ares_mx_reply **") parse_status = _lib.ares_parse_mx_reply(abuf, alen, mx_reply); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [] mx_reply_ptr = _ffi.new("struct ares_mx_reply **") mx_reply_ptr[0] = mx_reply[0] while True: if mx_reply_ptr[0] == _ffi.NULL: break result.append(ares_query_mx_result(mx_reply[0])) mx_reply_ptr[0] = mx_reply_ptr[0].next _lib.ares_free_data(mx_reply) status = None elif query_type == _lib.T_NAPTR: naptr_reply = _ffi.new("struct ares_naptr_reply **") parse_status = _lib.ares_parse_naptr_reply(abuf, alen, naptr_reply); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [] naptr_reply_ptr = _ffi.new("struct ares_naptr_reply **") naptr_reply_ptr[0] = naptr_reply[0] while True: if naptr_reply_ptr[0] == _ffi.NULL: break result.append(ares_query_naptr_result(naptr_reply[0])) naptr_reply_ptr[0] = naptr_reply_ptr[0].next _lib.ares_free_data(naptr_reply) status = None elif query_type == _lib.T_NS: hostent = _ffi.new("struct hostent **") parse_status = _lib.ares_parse_ns_reply(abuf, alen, hostent); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [] host = hostent[0] for i in range(100): if host.h_aliases[i] == _ffi.NULL: break result.append(ares_query_ns_result(host.h_aliases[i])) _lib.ares_free_hostent(host) status = None elif query_type == _lib.T_PTR: hostent = _ffi.new("struct hostent **") parse_status = _lib.ares_parse_ptr_reply(abuf, alen, _ffi.NULL, 0, socket.AF_UNSPEC, hostent); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = ares_query_ptr_result(hostent[0]) _lib.ares_free_hostent(hostent[0]) status = None elif query_type == _lib.T_SOA: soa_reply = _ffi.new("struct ares_soa_reply **") parse_status = _lib.ares_parse_soa_reply(abuf, alen, soa_reply); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = ares_query_soa_result(soa_reply[0]) _lib.ares_free_data(soa_reply[0]) status = None elif query_type == _lib.T_SRV: srv_reply = _ffi.new("struct ares_srv_reply **") parse_status = _lib.ares_parse_srv_reply(abuf, alen, srv_reply); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [] srv_reply_ptr = _ffi.new("struct ares_srv_reply **") srv_reply_ptr[0] = srv_reply[0] while True: if srv_reply_ptr[0] == _ffi.NULL: break result.append(ares_query_srv_result(srv_reply_ptr[0])) srv_reply_ptr[0] = srv_reply_ptr[0].next _lib.ares_free_data(srv_reply[0]) status = None elif query_type == _lib.T_TXT: txt_reply = _ffi.new("struct ares_txt_ext **") parse_status = _lib.ares_parse_txt_reply_ext(abuf, alen, txt_reply); if parse_status != ARES_SUCCESS: result = None status = parse_status else: result = [] txt_reply_ptr = _ffi.new("struct ares_txt_ext **") txt_reply_ptr[0] = txt_reply[0] tmp_obj = None while True: if txt_reply_ptr[0] == _ffi.NULL: if tmp_obj is not None: result.append(tmp_obj) break if txt_reply_ptr[0].record_start == 1: if tmp_obj is not None: result.append(tmp_obj) tmp_obj = ares_query_txt_result(txt_reply_ptr[0]) else: new_chunk = ares_query_txt_result(txt_reply_ptr[0]) tmp_obj.text += new_chunk.text txt_reply_ptr[0] = txt_reply_ptr[0].next _lib.ares_free_data(txt_reply[0]) status = None else: raise ValueError("invalid query type specified") callback(result, status) _global_set.discard(arg)