| 85 | } |
| 86 | |
| 87 | int |
| 88 | DNSConnection::connect(sockaddr const *addr, Options const &opt) |
| 89 | { |
| 90 | ink_assert(!this->sock.is_ok()); |
| 91 | ink_assert(ats_is_ip(addr)); |
| 92 | this->opt = opt; |
| 93 | this->tcp_data.reset(); |
| 94 | |
| 95 | int res = 0; |
| 96 | uint8_t af = addr->sa_family; |
| 97 | IpEndpoint bind_addr; |
| 98 | size_t bind_size = 0; |
| 99 | |
| 100 | if (opt._use_tcp) { |
| 101 | this->sock = UnixSocket{af, SOCK_STREAM, 0}; |
| 102 | } else { |
| 103 | this->sock = UnixSocket{af, SOCK_DGRAM, 0}; |
| 104 | } |
| 105 | |
| 106 | if (!this->sock.is_ok()) { |
| 107 | goto Lerror; |
| 108 | } |
| 109 | |
| 110 | memset(&bind_addr, 0, sizeof bind_addr); |
| 111 | bind_addr.sa.sa_family = af; |
| 112 | |
| 113 | if (AF_INET6 == af) { |
| 114 | if (ats_is_ip6(opt._local_ipv6)) { |
| 115 | ats_ip_copy(&bind_addr.sa, opt._local_ipv6); |
| 116 | } else { |
| 117 | bind_addr.sin6.sin6_addr = in6addr_any; |
| 118 | } |
| 119 | bind_size = sizeof(sockaddr_in6); |
| 120 | } else if (AF_INET == af) { |
| 121 | if (ats_is_ip4(opt._local_ipv4)) { |
| 122 | ats_ip_copy(&bind_addr.sa, opt._local_ipv4); |
| 123 | } else { |
| 124 | bind_addr.sin.sin_addr.s_addr = INADDR_ANY; |
| 125 | } |
| 126 | bind_size = sizeof(sockaddr_in); |
| 127 | } else { |
| 128 | ink_assert(!"Target DNS address must be IP."); |
| 129 | } |
| 130 | |
| 131 | if (opt._bind_random_port) { |
| 132 | int retries = 0; |
| 133 | while (retries++ < 10000) { |
| 134 | ip_port_text_buffer b; |
| 135 | uint32_t p = generator.random(); |
| 136 | p = static_cast<uint16_t>((p % (LAST_RANDOM_PORT - FIRST_RANDOM_PORT)) + FIRST_RANDOM_PORT); |
| 137 | ats_ip_port_cast(&bind_addr.sa) = htons(p); // stuff port in sockaddr. |
| 138 | Dbg(dbg_ctl_dns, "random port = %s", ats_ip_nptop(&bind_addr.sa, b, sizeof b)); |
| 139 | if (this->sock.bind(&bind_addr.sa, bind_size) < 0) { |
| 140 | continue; |
| 141 | } |
| 142 | goto Lok; |
| 143 | } |
| 144 | Warning("unable to bind random DNS port"); |
no test coverage detected