main.c (6120B)
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <string.h> 4 #include <curl/curl.h> 5 #define LIB_STR_IMPL 6 #include <libstr.h> 7 8 #define DNS_ENV_UPDATE "DNS_UPDATE_URL" 9 #define DNS_ENV_LOOKUP "DNS_LOOKUP_URL" 10 #define DNS_ENV_RESOLVE "DNS_RESOLVE_URL" 11 12 #define DNS_SYMBOL_HOST "HOST" 13 #define DNS_SYMBOL_DOMAIN "DOMAIN" 14 #define DNS_SYMBOL_IP_ADDR "IP_ADDR" 15 #define DNS_SYMBOL_PASSWD "PASSWD" 16 17 #define DNS_DOMAIN_WILDCARD "@" 18 19 typedef enum { 20 DNS_ERR_OK, 21 DNS_ERR_FAIL, 22 } dns_error_t; 23 24 typedef struct { 25 char *host; 26 char *domain; 27 char *passwd; 28 } dns_domain_t; 29 30 size_t dns_curl_write(void *ptr, size_t size, size_t nmemb, void *data) { 31 size_t len = size * nmemb; 32 char **curl_data = (char **) data; 33 str_append_len(curl_data, ptr, len); 34 return len; 35 } 36 37 dns_error_t dns_update(char *url, dns_domain_t *domain, char *ip_addr) { 38 CURL *curl = curl_easy_init(); 39 if (!curl) { 40 fprintf(stderr, "CURL init failed!\n"); 41 return DNS_ERR_FAIL; 42 } 43 char *resolved_url = url; 44 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_HOST "}", domain->host); 45 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_DOMAIN "}", domain->domain); 46 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_PASSWD "}", domain->passwd); 47 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_IP_ADDR "}", ip_addr); 48 char *curl_data = NULL; 49 curl_easy_setopt(curl, CURLOPT_URL, resolved_url); 50 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dns_curl_write); 51 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curl_data); 52 CURLcode code = curl_easy_perform(curl); 53 free(resolved_url); 54 if (code != CURLE_OK) { 55 curl_easy_cleanup(curl); 56 fprintf(stderr, "CURL fetch failed!\n%s\n", curl_easy_strerror(code)); 57 return DNS_ERR_FAIL; 58 } 59 curl_easy_cleanup(curl); 60 for (size_t i = 0; i < strlen(curl_data); i++) { 61 if (strncmp(curl_data + i, "<ErrCount>0</ErrCount>", 22) == 0) { 62 free(curl_data); 63 return DNS_ERR_OK; 64 } 65 } 66 fprintf(stderr, "DNS update error:\n%s\n", curl_data); 67 if (curl_data != NULL) { 68 free(curl_data); 69 } 70 return DNS_ERR_FAIL; 71 } 72 73 dns_error_t dns_lookup(char *url, dns_domain_t *domain, char **ip_addr) { 74 CURL *curl = curl_easy_init(); 75 if (!curl) { 76 fprintf(stderr, "CURL init failed!\n"); 77 return DNS_ERR_FAIL; 78 } 79 char *resolved_url = url; 80 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_HOST "}", domain->host); 81 resolved_url = str_replace_all(resolved_url, "{" DNS_SYMBOL_DOMAIN "}", domain->domain); 82 char *curl_data = NULL; 83 curl_easy_setopt(curl, CURLOPT_URL, resolved_url); 84 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dns_curl_write); 85 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curl_data); 86 CURLcode code = curl_easy_perform(curl); 87 free(resolved_url); 88 if (code != CURLE_OK) { 89 curl_easy_cleanup(curl); 90 fprintf(stderr, "CURL fetch failed!\n%s\n", curl_easy_strerror(code)); 91 return DNS_ERR_FAIL; 92 } 93 curl_easy_cleanup(curl); 94 size_t set = 0; 95 for (size_t i = 0; i < strlen(curl_data);) { 96 if (strncmp(curl_data + i, "\"data\":\"", 8) == 0) { 97 i += 8; 98 set = i; 99 continue; 100 } 101 if (set > 0 && curl_data[i] == '"') { 102 str_append_len(ip_addr, curl_data + set, i - set); 103 break; 104 } 105 i++; 106 } 107 if (curl_data != NULL) { 108 free(curl_data); 109 } 110 return DNS_ERR_OK; 111 } 112 113 dns_error_t dns_resolve(char *url, char **ip_addr) { 114 CURL *curl = curl_easy_init(); 115 if (!curl) { 116 fprintf(stderr, "CURL init failed!\n"); 117 return DNS_ERR_FAIL; 118 } 119 char *curl_data = NULL; 120 curl_easy_setopt(curl, CURLOPT_URL, url); 121 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, dns_curl_write); 122 curl_easy_setopt(curl, CURLOPT_WRITEDATA, &curl_data); 123 CURLcode code = curl_easy_perform(curl); 124 if (code != CURLE_OK) { 125 curl_easy_cleanup(curl); 126 fprintf(stderr, "CURL fetch failed!\n%s\n", curl_easy_strerror(code)); 127 return DNS_ERR_FAIL; 128 } 129 curl_easy_cleanup(curl); 130 for (size_t i = 0; i < strlen(curl_data); i++) { 131 if (curl_data[i] == '\n') { 132 str_append_len(ip_addr, curl_data, i); 133 break; 134 } 135 } 136 if (curl_data != NULL) { 137 free(curl_data); 138 } 139 return DNS_ERR_OK; 140 } 141 142 int main(int argc, char **argv) { 143 if (argc != 4) { 144 fprintf(stderr, "Invalid arguments!\nUsage: dns <host> <domain> <passwd>\n"); 145 return EXIT_FAILURE; 146 } 147 dns_domain_t domain = { 148 .host = argv[1], 149 .domain = argv[2], 150 .passwd = argv[3], 151 }; 152 if (strcmp(domain.host, DNS_DOMAIN_WILDCARD) == 0) { 153 fprintf(stdout, "DNS domain: %s\n", domain.domain); 154 } 155 else { 156 fprintf(stdout, "DNS domain: %s.%s\n", domain.host, domain.domain); 157 } 158 char *dns_update_url = getenv(DNS_ENV_UPDATE); 159 if (dns_update_url == NULL) { 160 fprintf(stderr, "Environment variable missing!\nDefine: " DNS_ENV_UPDATE "\n"); 161 return EXIT_FAILURE; 162 } 163 char *dns_lookup_url = getenv(DNS_ENV_LOOKUP); 164 if (dns_lookup_url == NULL) { 165 fprintf(stderr, "Environment variable missing!\nDefine: " DNS_ENV_LOOKUP "\n"); 166 return EXIT_FAILURE; 167 } 168 char *dns_resolve_url = getenv(DNS_ENV_RESOLVE); 169 if (dns_resolve_url == NULL) { 170 fprintf(stderr, "Environment variable missing!\nDefine: " DNS_ENV_RESOLVE "\n"); 171 return EXIT_FAILURE; 172 } 173 char *ip_addr = NULL; 174 if (dns_resolve(dns_resolve_url, &ip_addr) != DNS_ERR_OK) { 175 fprintf(stderr, "IP address resolution failed!\n"); 176 return EXIT_FAILURE; 177 } 178 fprintf(stdout, "DNS resolve IP_ADDR: %s\n", ip_addr); 179 char *domain_ip_addr = NULL; 180 if (dns_lookup(dns_lookup_url, &domain, &domain_ip_addr) != DNS_ERR_OK) { 181 fprintf(stderr, "DNS lookup failed!\n"); 182 return EXIT_FAILURE; 183 } 184 fprintf(stdout, "DNS lookup DOMAIN_IP_ADDR: %s\n", domain_ip_addr); 185 if (strcmp(ip_addr, domain_ip_addr) != 0) { 186 if (dns_update(dns_update_url, &domain, ip_addr) != DNS_ERR_OK) { 187 free(ip_addr); 188 free(domain_ip_addr); 189 fprintf(stderr, "DNS update FAILED!\n"); 190 return EXIT_FAILURE; 191 } 192 fprintf(stdout, "DNS update SUCCESSFUL.\n"); 193 } 194 else { 195 fprintf(stdout, "DNS domain already UP-TO-DATE.\n"); 196 } 197 free(ip_addr); 198 free(domain_ip_addr); 199 return EXIT_SUCCESS; 200 }