void strategy_update_remote_addr_list(vpn_ctx_t *ctx) { int i; time_t now; struct sockaddr *remote_addrp = ctx->remote_addrp; time(&now); socklen_t remote_addrlen = ctx->remote_addrlen; // if already in list, update time and return for (i = 0; i < ctx->nknown_addr; i++) { if (remote_addrlen == ctx->known_addrs[i].addrlen) { if (0 == memcmp(remote_addrp, &ctx->known_addrs[i].addr, remote_addrlen)) { ctx->known_addrs[i].last_recv_time = now; return; } } } // if address list is not full, just append remote addr if (ctx->nknown_addr < ctx->args->concurrency) { save_addr(&ctx->known_addrs[ctx->nknown_addr], remote_addrp, remote_addrlen, now); ctx->nknown_addr++; return; } // if full, replace the oldest addr_info_t *oldest_addr_info = NULL; for (i = 0; i < ctx->nknown_addr; i++) { if (oldest_addr_info == NULL || oldest_addr_info->last_recv_time > ctx->known_addrs[i].last_recv_time) { oldest_addr_info = &ctx->known_addrs[i]; } } if (oldest_addr_info) { save_addr(oldest_addr_info, remote_addrp, remote_addrlen, now); } }
static ad_disc_cds_t * srv_parse(uchar_t *msg, int len, int *scnt, int *maxcnt) { ad_disc_cds_t *cds; ad_disc_cds_t *cds_res = NULL; HEADER *hdr; int i, qdcount, ancount, nscount, arcount; uchar_t *ptr, *eom; uchar_t *end; uint16_t type; /* LINTED E_FUNC_SET_NOT_USED */ uint16_t class __unused; uint32_t rttl; uint16_t size; char namebuf[NS_MAXDNAME]; eom = msg + len; hdr = (void *)msg; ptr = msg + sizeof (HEADER); qdcount = ntohs(hdr->qdcount); ancount = ntohs(hdr->ancount); nscount = ntohs(hdr->nscount); arcount = ntohs(hdr->arcount); /* skip the question section */ len = ns_skiprr(ptr, eom, ns_s_qd, qdcount); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); return (NULL); } ptr += len; /* * Walk through the answer section, building the result array. * The array size is +2 because we (possibly) add the preferred * DC if it was not there, and an empty one (null termination). */ *maxcnt = ancount + 2; cds_res = calloc(*maxcnt, sizeof (*cds_res)); if (cds_res == NULL) { logger(LOG_ERR, "Out of memory"); return (NULL); } cds = cds_res; for (i = 0; i < ancount; i++) { len = dn_expand(msg, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; NS_GET16(type, ptr); NS_GET16(class, ptr); NS_GET32(rttl, ptr); NS_GET16(size, ptr); if ((end = ptr + size) > eom) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } if (type != T_SRV) { ptr = end; continue; } NS_GET16(cds->cds_ds.priority, ptr); NS_GET16(cds->cds_ds.weight, ptr); NS_GET16(cds->cds_ds.port, ptr); len = dn_expand(msg, eom, ptr, cds->cds_ds.host, sizeof (cds->cds_ds.host)); if (len < 0) { logger(LOG_ERR, "DNS query invalid SRV record"); goto err; } cds->cds_ds.ttl = rttl; if (DBG(DNS, 2)) { logger(LOG_DEBUG, " %s", namebuf); logger(LOG_DEBUG, " ttl=%d pri=%d weight=%d %s:%d", rttl, cds->cds_ds.priority, cds->cds_ds.weight, cds->cds_ds.host, cds->cds_ds.port); } cds++; /* move ptr to the end of current record */ ptr = end; } *scnt = (cds - cds_res); /* skip the nameservers section (if any) */ len = ns_skiprr(ptr, eom, ns_s_ns, nscount); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; /* walk through the additional records */ for (i = 0; i < arcount; i++) { sa_family_t af; len = dn_expand(msg, eom, ptr, namebuf, sizeof (namebuf)); if (len < 0) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } ptr += len; NS_GET16(type, ptr); NS_GET16(class, ptr); NS_GET32(rttl, ptr); NS_GET16(size, ptr); if ((end = ptr + size) > eom) { logger(LOG_ERR, "DNS query invalid message format"); goto err; } switch (type) { case ns_t_a: af = AF_INET; break; case ns_t_aaaa: af = AF_INET6; break; default: continue; } if (DBG(DNS, 2)) { char abuf[INET6_ADDRSTRLEN]; const char *ap; ap = inet_ntop(af, ptr, abuf, sizeof (abuf)); logger(LOG_DEBUG, " %s %s %s", (af == AF_INET) ? "A " : "AAAA", (ap) ? ap : "?", namebuf); } /* Find the server, add to its address list. */ for (cds = cds_res; cds->cds_ds.host[0] != '\0'; cds++) if (0 == strcmp(namebuf, cds->cds_ds.host)) save_addr(cds, af, ptr, size); /* move ptr to the end of current record */ ptr = end; } return (cds_res); err: free(cds_res); return (NULL); }