Skip to content

Instantly share code, notes, and snippets.

@KJTsanaktsidis
Created November 21, 2022 06:57
Show Gist options
  • Save KJTsanaktsidis/668247fd898cec57f9d280b0222438ae to your computer and use it in GitHub Desktop.
Save KJTsanaktsidis/668247fd898cec57f9d280b0222438ae to your computer and use it in GitHub Desktop.
glibc dns timeout reproduction
#include <curl/curl.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define NUM_THREADS 20
static pthread_mutex_t outlock = PTHREAD_MUTEX_INITIALIZER;
static int skip_dns = 0;
struct write_cb_data {
char buf[11];
size_t buf_written;
};
size_t write_cb(char *ptr, size_t elsize, size_t nmeb, void *ctxarg) {
size_t sz = elsize * nmeb;
struct write_cb_data *ctx = ctxarg;
size_t to_write = sz;
if (to_write > sizeof(ctx->buf) - 1 - ctx->buf_written) {
to_write = sizeof(ctx->buf) - 1 - ctx->buf_written;
}
if (to_write > 0) {
memcpy(ctx->buf + ctx->buf_written, ptr, to_write);
}
ctx->buf_written += to_write;
return sz;
}
void *worker(void *ctx) {
int worker_nr = *((int *)ctx);
pthread_mutex_lock(&outlock);
printf("[%d] starting\n", worker_nr);
pthread_mutex_unlock(&outlock);
CURL *curl = curl_easy_init();
if (!curl) {
pthread_mutex_lock(&outlock);
printf("[%d] curl_easy_init failed\n", worker_nr);
pthread_mutex_unlock(&outlock);
return NULL;
}
char errbuf[CURL_ERROR_SIZE] = {0};
struct write_cb_data writectx = {0};
curl_easy_setopt(curl, CURLOPT_URL, "http://example.com");
struct curl_slist *dns_cache = curl_slist_append(NULL, "example.com:80:93.184.216.34");
if (skip_dns) {
curl_easy_setopt(curl, CURLOPT_RESOLVE, dns_cache);
}
curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errbuf);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_cb);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &writectx);
CURLcode res = curl_easy_perform(curl);
curl_slist_free_all(dns_cache);
if (res != CURLE_OK) {
pthread_mutex_lock(&outlock);
printf("[%d] curl_easy_perform failed: %d (%s)\n", worker_nr, res, errbuf);
pthread_mutex_unlock(&outlock);
return NULL;
}
pthread_mutex_lock(&outlock);
printf("[%d] output: %s\n", worker_nr, writectx.buf);
pthread_mutex_unlock(&outlock);
return NULL;
}
int main(int argc, char **argv) {
curl_global_init(CURL_GLOBAL_NOTHING);
if (argc > 1 && strcmp(argv[1], "--skip-dns") == 0) {
skip_dns = 1;
}
printf("skip_dns: %d\n", skip_dns);
printf("PID is %d: hit enter to start", getpid());
fflush(stdout);
while (getchar() != '\n') {}
pthread_t threads[NUM_THREADS] = {0};
int ids[NUM_THREADS];
for (int i = 0; i < NUM_THREADS; i++) {
ids[i] = i;
int r = pthread_create(&threads[i], NULL, worker, &ids[i]);
if (r != 0) {
pthread_mutex_lock(&outlock);
char errbuf[256];
printf("pthread_create %d failed: %s\n", i, strerror_r(r, errbuf, sizeof(errbuf)));
pthread_mutex_unlock(&outlock);
fflush(stdout);
abort();
}
}
for (int i = 0; i < NUM_THREADS; i++) {
int r = pthread_join(threads[i], NULL);
if (r != 0) {
pthread_mutex_lock(&outlock);
char errbuf[256];
printf("pthread_join %d failed: %s\n", i, strerror_r(r, errbuf, sizeof(errbuf)));
pthread_mutex_unlock(&outlock);
fflush(stdout);
abort();
}
pthread_mutex_lock(&outlock);
printf("[%d] joined\n", i);
pthread_mutex_unlock(&outlock);
}
printf("hit enter to exit");
fflush(stdout);
while (getchar() != '\n') {}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment