<commit_before>#include <fcntl.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>

typedef struct {
  time_t ts;
  char *buf;
  size_t buflen;
  struct sockaddr *addr;
  socklen_t addrlen;
} delay_buf_t;

typedef struct {
  uint16_t id;
  struct sockaddr *addr;
  socklen_t addrlen;
} id_addr_t;

typedef struct {
  int entries;
  struct in_addr *ips;
} ip_list_t;

// avoid malloc and free
#define BUF_SIZE 2048
static char global_buf[BUF_SIZE];

static int verbose = 0;

static const char *version = "ChinaDNS 1.0.0";

static const char *default_dns_servers =
  "172.16.17.32,8.8.8.8,208.67.222.222";
static char *dns_servers = NULL;
static int dns_servers_len;
static id_addr_t *dns_server_addrs;

static int parse_args(int argc, char **argv);

static int setnonblock(int sock);
static int resolve_dns_servers();

static const char *default_listen_addr = "0.0.0.0";
static const char *default_listen_port = "53";

static char *listen_addr = NULL;
static char *listen_port = NULL;

static const char *default_ip_list_file = "iplist.txt";
static char *ip_list_file = NULL;
static ip_list_t ip_list;
static int parse_ip_list();

static int dns_init_sockets();
static void dns_handle_local();
static void dns_handle_remote();

static const char *hostname_from_question(ns_msg msg);
static int should_filter_query(ns_msg msg);

static void queue_add(id_addr_t id_addr);
static id_addr_t *queue_lookup(uint16_t id);

#define ID_ADDR_QUEUE_LEN 128
// use a queue instead of hash here since it's not long
static id_addr_t id_addr_queue[ID_ADDR_QUEUE_LEN];
static int id_addr_queue_pos = 0;

#define EMPTY_RESULT_DELAY 3
#define DELAY_QUEUE_LEN 32
static delay_buf_t delay_queue[DELAY_QUEUE_LEN];
static void schedule_delay(const char *buf, size_t buflen,
                           struct sockaddr *addr, socklen_t addrlen);
static void check_and_send_delay();
static void free_delay(int pos);
// next position for first, not used
static int delay_queue_first = 0;
// current position for last, used
static int delay_queue_last = 0;

static int local_sock;
static int remote_sock;

static const char *help_message =
  "usage: chinadns [-h] [-l IPLIST_FILE] [-b BIND_ADDR] [-p BIND_PORT]\n"
  "       [-s DNS] [-v]\n"
  "Forward DNS requests.\n"
  "\n"
  "  -h, --help            show this help message and exit\n"
  "  -l IPLIST_FILE        path to ip blacklist file\n"
  "  -b BIND_ADDR          address that listens, default: 127.0.0.1\n"
  "  -p BIND_PORT          port that listens, default: 53\n"
  "  -s DNS                DNS servers to use, default:\n"
  "                        172.16.17.32,208.67.222.222,8.8.8.8\n"
  "  -v                    verbose logging\n"
  "\n"
  "Online help: <https://github.com/clowwindy/ChinaDNS-C>\n";

#define __LOG(o, t, v, s...) do {                                   \
  time_t now;                                                       \
  time(&now);                                                       \
  char *time_str = ctime(&now);                                     \
  time_str[strlen(time_str) - 1] = '\0';                            \
  if (t == 0) {                                                     \
    if (verbose) {                                                  \
      fprintf(o, "%s ", time_str);                                  \
      printf(s);                                                    \
    }                                                               \
  } else if (t == 1) {                                              \
    fprintf(o, "%s %s:%d ", time_str, __FILE__, __LINE__);          \
    perror(v);                                                      \
  }                                                                 \
} while (0)

#define LOG(s...) __LOG(stdout, 0, "", s)
#define ERR(s) __LOG(stderr, 1, s, "")
#define VERR(s...) __LOG(stderr, 0, "", s)

int main(int argc, char **argv) {
  fd_set readset, errorset;
  int max_fd;

  memset(&id_addr_queue, 0, sizeof(id_addr_queue));
  memset(&delay_queue, 0, sizeof(delay_queue));
  if (0 != parse_args(argc, argv))
    return EXIT_FAILURE;
  if (0 != parse_ip_list())
    return EXIT_FAILURE;
  if (0 != resolve_dns_servers())
    return EXIT_FAILURE;
  if (0 != dns_init_sockets())
    return EXIT_FAILURE;

  printf("%s\n", version);
  max_fd = MAX(local_sock, remote_sock) + 1;
  while (1) {
    FD_ZERO(&readset);
    FD_ZERO(&errorset);
    FD_SET(local_sock, &readset);
    FD_SET(local_sock, &errorset);
    FD_SET(remote_sock, &readset);
    FD_SET(remote_sock, &errorset);
    struct timeval timeout = {<commit_msg>make compiler happy<commit_after>#include <fcntl.h>
#include <netdb.h>
#include <resolv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <sys/types.h>

typedef struct {
  time_t ts;
  char *buf;
  size_t buflen;
  struct sockaddr *addr;
  socklen_t addrlen;
} delay_buf_t;

typedef struct {
  uint16_t id;
  struct sockaddr *addr;
  socklen_t addrlen;
} id_addr_t;

typedef struct {
  int entries;
  struct in_addr *ips;
} ip_list_t;

// avoid malloc and free
#define BUF_SIZE 2048
static char global_buf[BUF_SIZE];

static int verbose = 0;

static const char *version = "ChinaDNS 1.0.0";

static const char *default_dns_servers =
  "172.16.17.32,8.8.8.8,208.67.222.222";
static char *dns_servers = NULL;
static int dns_servers_len;
static id_addr_t *dns_server_addrs;

static int parse_args(int argc, char **argv);

static int setnonblock(int sock);
static int resolve_dns_servers();

static const char *default_listen_addr = "0.0.0.0";
static const char *default_listen_port = "53";

static char *listen_addr = NULL;
static char *listen_port = NULL;

static const char *default_ip_list_file = "iplist.txt";
static char *ip_list_file = NULL;
static ip_list_t ip_list;
static int parse_ip_list();

static int dns_init_sockets();
static void dns_handle_local();
static void dns_handle_remote();

static const char *hostname_from_question(ns_msg msg);
static int should_filter_query(ns_msg msg);

static void queue_add(id_addr_t id_addr);
static id_addr_t *queue_lookup(uint16_t id);

#define ID_ADDR_QUEUE_LEN 128
// use a queue instead of hash here since it's not long
static id_addr_t id_addr_queue[ID_ADDR_QUEUE_LEN];
static int id_addr_queue_pos = 0;

#define EMPTY_RESULT_DELAY 3
#define DELAY_QUEUE_LEN 32
static delay_buf_t delay_queue[DELAY_QUEUE_LEN];
static void schedule_delay(const char *buf, size_t buflen,
                           struct sockaddr *addr, socklen_t addrlen);
static void check_and_send_delay();
static void free_delay(int pos);
// next position for first, not used
static int delay_queue_first = 0;
// current position for last, used
static int delay_queue_last = 0;

static int local_sock;
static int remote_sock;

static const char *help_message =
  "usage: chinadns [-h] [-l IPLIST_FILE] [-b BIND_ADDR] [-p BIND_PORT]\n"
  "       [-s DNS] [-v]\n"
  "Forward DNS requests.\n"
  "\n"
  "  -h, --help            show this help message and exit\n"
  "  -l IPLIST_FILE        path to ip blacklist file\n"
  "  -b BIND_ADDR          address that listens, default: 127.0.0.1\n"
  "  -p BIND_PORT          port that listens, default: 53\n"
  "  -s DNS                DNS servers to use, default:\n"
  "                        172.16.17.32,208.67.222.222,8.8.8.8\n"
  "  -v                    verbose logging\n"
  "\n"
  "Online help: <https://github.com/clowwindy/ChinaDNS-C>\n";

#define __LOG(o, t, v, s...) do {                                   \
  time_t now;                                                       \
  time(&now);                                                       \
  char *time_str = ctime(&now);                                     \
  time_str[strlen(time_str) - 1] = '\0';                            \
  if (t == 0) {                                                     \
    if (verbose) {                                                  \
      fprintf(o, "%s ", time_str);                                  \
      printf(s);                                                    \
    }                                                               \
  } else if (t == 1) {                                              \
    fprintf(o, "%s %s:%d ", time_str, __FILE__, __LINE__);          \
    perror(v);                                                      \
  }                                                                 \
} while (0)

#define LOG(s...) __LOG(stdout, 0, "_", s)
#define ERR(s) __LOG(stderr, 1, s, "_")
#define VERR(s...) __LOG(stderr, 0, "_", s)

int main(int argc, char **argv) {
  fd_set readset, errorset;
  int max_fd;

  memset(&id_addr_queue, 0, sizeof(id_addr_queue));
  memset(&delay_queue, 0, sizeof(delay_queue));
  if (0 != parse_args(argc, argv))
    return EXIT_FAILURE;
  if (0 != parse_ip_list())
    return EXIT_FAILURE;
  if (0 != resolve_dns_servers())
    return EXIT_FAILURE;
  if (0 != dns_init_sockets())
    return EXIT_FAILURE;

  printf("%s\n", version);
  max_fd = MAX(local_sock, remote_sock) + 1;
  while (1) {
    FD_ZERO(&readset);
    FD_ZERO(&errorset);
    FD_SET(local_sock, &readset);
    FD_SET(local_sock, &errorset);
    FD_SET(remote_sock, &readset);
    FD_SET(remote_sock, &errorset);
    struct timeval timeout = {
{'fraction_non_alphanumeric': 0.11567125013120605, 'fraction_numerical': 0.020783037682376403, 'mean_word_length': 2.110675808031342, 'pattern_counts': {'":': 0, '<': 29, '<?xml version=': 0, '>': 29, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 16, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 40, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7341054', 'n_tokens_mistral': 3330, 'n_tokens_neox': 3187, 'n_words': 824}