Look up external IP via DNS instead of HTTP
Use myip.opendns.com via their resolver. The code is now TCP free again :)
This commit is contained in:
parent
e8a4c66719
commit
2032b44949
|
@ -13,11 +13,11 @@ master:
|
|||
- README converted to markdown by Nicolas Braud-Santoni.
|
||||
- Linux: use pkg-config for systemd support flags.
|
||||
Patch by Jason A. Donenfeld.
|
||||
- Change external IP webservice to ipify.org
|
||||
- Add support for IPv6 in the server.
|
||||
Raw mode will be with same protocol as used for login.
|
||||
Traffic inside tunnel is still IPv4.
|
||||
- Update android build to support 5.0 (Lollipop) and newer.
|
||||
- Change external IP lookup to using myip.opendns.com via DNS.
|
||||
|
||||
2014-06-16: 0.7.0 "Kryoptonite"
|
||||
- Partial IPv6 support (#107)
|
||||
|
|
|
@ -286,7 +286,7 @@ You must make sure the dns requests are forwarded to this port yourself.
|
|||
.B -n auto|external_ip
|
||||
The IP address to return in NS responses. Default is to return the address used
|
||||
as destination in the query.
|
||||
If external_ip is 'auto', iodined will use ipify.org web service to
|
||||
If external_ip is 'auto', iodined will use the opendns.com DNS service to
|
||||
retrieve the external IP of the host and use that for NS responses.
|
||||
.TP
|
||||
.B -b dnsport
|
||||
|
|
15
src/dns.c
15
src/dns.c
|
@ -492,6 +492,8 @@ int dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet,
|
|||
readlong(packet, &data, &ttl);
|
||||
readshort(packet, &data, &rlen);
|
||||
|
||||
if (type == T_CNAME) {
|
||||
/* For tunnels, query type A has CNAME type answer */
|
||||
memset(name, 0, sizeof(name));
|
||||
readname(packet, packetlen, &data, name, sizeof(name) - 1);
|
||||
name[sizeof(name)-1] = '\0';
|
||||
|
@ -499,6 +501,19 @@ int dns_decode(char *buf, size_t buflen, struct query *q, qr_t qr, char *packet,
|
|||
buf[buflen - 1] = '\0';
|
||||
rv = strlen(buf);
|
||||
}
|
||||
if (type == T_A) {
|
||||
/* Answer type A includes only 4 bytes.
|
||||
Not used for tunneling. */
|
||||
rv = MIN(rlen, sizeof(rdata));
|
||||
rv = readdata(packet, &data, rdata, rv);
|
||||
if (rv >= 2 && buf) {
|
||||
rv = MIN(rv, buflen);
|
||||
memcpy(buf, rdata, rv);
|
||||
} else {
|
||||
rv = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((type == T_MX || type == T_SRV) && buf) {
|
||||
/* We support 250 records, 250*(255+header) ~= 64kB.
|
||||
Only exact 10-multiples are accepted, and gaps in
|
||||
|
|
|
@ -123,57 +123,57 @@ get_dns_fd(struct dnsfd *fds, struct sockaddr_storage *addr)
|
|||
return fds->v4fd;
|
||||
}
|
||||
|
||||
/* Ask ipify.org webservice to get external ip */
|
||||
/* Ask opendns.com DNS service for external ip */
|
||||
static int
|
||||
get_external_ip(struct in_addr *ip)
|
||||
{
|
||||
int sock;
|
||||
struct addrinfo *addr;
|
||||
static const char target[] = "myip.opendns.com";
|
||||
struct query query;
|
||||
int attempt;
|
||||
int res;
|
||||
const char *getstr = "GET / HTTP/1.0\r\n"
|
||||
/* HTTP 1.0 to avoid chunked transfer coding */
|
||||
"Host: api.ipify.org\r\n\r\n";
|
||||
char buf[512];
|
||||
char *b;
|
||||
int len;
|
||||
int fd;
|
||||
int out_len = 0;
|
||||
memset(&query, 0, sizeof(query));
|
||||
|
||||
res = getaddrinfo("api.ipify.org", "80", NULL, &addr);
|
||||
query.type = T_A;
|
||||
res = get_addr("resolver1.opendns.com", 53, AF_INET, 0, &query.destination);
|
||||
if (res < 0) return 1;
|
||||
query.dest_len = res;
|
||||
|
||||
sock = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
|
||||
if (sock < 0) {
|
||||
freeaddrinfo(addr);
|
||||
return 2;
|
||||
fd = open_dns_from_host(NULL, 0, AF_INET, AI_PASSIVE);
|
||||
if (fd < 0) return 2;
|
||||
|
||||
for (attempt = 0; attempt < 3; attempt++) {
|
||||
char buf[64*1024];
|
||||
int buflen;
|
||||
fd_set fds;
|
||||
struct timeval tv;
|
||||
|
||||
if (attempt) fprintf(stderr, "Retrying external IP lookup\n");
|
||||
query.id = rand();
|
||||
buflen = sizeof(buf);
|
||||
buflen = dns_encode(buf, buflen, &query, QR_QUERY, target, strlen(target));
|
||||
if (buflen < 0) continue;
|
||||
|
||||
sendto(fd, buf, buflen, 0, (struct sockaddr*)&query.destination, query.dest_len);
|
||||
|
||||
tv.tv_sec = 1 + attempt;
|
||||
tv.tv_usec = 0;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(fd, &fds);
|
||||
res = select(fd + 1, &fds, NULL, NULL, &tv);
|
||||
if (res > 0) {
|
||||
buflen = sizeof(buf);
|
||||
buflen = recv(fd, buf, buflen, 0);
|
||||
if (buflen > 0) {
|
||||
out_len = dns_decode((char *)ip, sizeof(struct in_addr), &query, QR_ANSWER, buf, buflen);
|
||||
if (out_len > 0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res = connect(sock, addr->ai_addr, addr->ai_addrlen);
|
||||
freeaddrinfo(addr);
|
||||
if (res < 0) return 3;
|
||||
|
||||
res = write(sock, getstr, strlen(getstr));
|
||||
if (res != strlen(getstr)) return 4;
|
||||
|
||||
/* Zero buf before receiving, leave at least one zero at the end */
|
||||
memset(buf, 0, sizeof(buf));
|
||||
res = read(sock, buf, sizeof(buf) - 1);
|
||||
if (res < 0) return 5;
|
||||
len = res;
|
||||
|
||||
res = close(sock);
|
||||
if (res < 0) return 6;
|
||||
|
||||
b = buf;
|
||||
while (len > 9) {
|
||||
/* Look for split between headers and data */
|
||||
if (strncmp("\r\n\r\n", b, 4) == 0) break;
|
||||
b++;
|
||||
len--;
|
||||
}
|
||||
if (len < 10) return 7;
|
||||
b += 4;
|
||||
|
||||
res = inet_aton(b, ip);
|
||||
return (res == 0);
|
||||
close_dns(fd);
|
||||
return (out_len != sizeof(struct in_addr));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2616,7 +2616,7 @@ main(int argc, char **argv)
|
|||
struct in_addr extip;
|
||||
int res = get_external_ip(&extip);
|
||||
if (res) {
|
||||
fprintf(stderr, "Failed to get external IP via web service.\n");
|
||||
fprintf(stderr, "Failed to get external IP via DNS query.\n");
|
||||
exit(3);
|
||||
}
|
||||
ns_ip = extip.s_addr;
|
||||
|
|
Loading…
Reference in New Issue