/** MAIN - Dyn DNS update entry point Actions: - read the configuration options - perform various init actions as specified in the options - create and init dyn_dns object. - launch the IP update action loop */ int dyn_dns_main(DYN_DNS_CLIENT *p_dyndns, int argc, char* argv[]) { FILE *fp; RC_TYPE rc = RC_OK; int i, s; int iterations_err = 0; char name[DYNDNS_SERVER_NAME_LENGTH]; if (p_dyndns == NULL) { return RC_INVALID_POINTER; } /* Create pid and cache file repository. */ mkdir(DYNDNS_RUNTIME_DATA_DIR, 0755); /* read cmd line options and set object properties */ rc = get_config_data(p_dyndns, argc, argv); if (rc != RC_OK || p_dyndns->abort) { return rc; } if (p_dyndns->change_persona) { OS_USER_INFO os_usr_info; memset(&os_usr_info, 0, sizeof(os_usr_info)); os_usr_info.gid = p_dyndns->sys_usr_info.gid; os_usr_info.uid = p_dyndns->sys_usr_info.uid; rc = os_change_persona(&os_usr_info); if (rc != RC_OK) { return rc; } } /* if logfile provided, redirect output to log file */ if (strlen(p_dyndns->dbg.p_logfilename) != 0) { rc = os_open_dbg_output(DBG_FILE_LOG, "", p_dyndns->dbg.p_logfilename); if (rc != RC_OK) { return rc; } } if (p_dyndns->debug_to_syslog == TRUE || (p_dyndns->run_in_background == TRUE)) { if (get_dbg_dest() == DBG_STD_LOG) /* avoid file and syslog output */ { rc = os_open_dbg_output(DBG_SYS_LOG, "inadyn", NULL); if (rc != RC_OK) { return rc; } } } /* if silent required, close console window */ if (p_dyndns->run_in_background == TRUE) { rc = close_console_window(); if (rc != RC_OK) { return rc; } if (get_dbg_dest() == DBG_SYS_LOG) { fclose(stdout); } } /* Create files with permissions 0644 */ umask(S_IWGRP | S_IWOTH); /* write pid file */ fp = fopen(p_dyndns->pidfile, "w"); if (!fp) { logit(LOG_ERR, MODULE_TAG "Failed opening pidfile %s for writing: %s", p_dyndns->pidfile, strerror(errno)); return RC_ERROR; } fprintf(fp, "%u", getpid()); fclose(fp); dyn_dns_print_hello(); /* At boot, or when restarting inadyn at runtime, the memory struct holding * our current IP# is empty. We want to avoid unnecessary updates of our * DDNS server record, since we might get locked out for abuse, so we "seed" * each of the DDNS records of our struct with the cached IP# from our cache * file, or from a regular DNS query. */ fp = fopen(p_dyndns->cachefile, "r"); if (!fp) { struct addrinfo hints; struct addrinfo *result; /* Clear DNS cache before querying for the IP below. */ res_init(); /* Try a DNS lookup of our last known IP#. */ for (i = 0; i < p_dyndns->info_count; i++) { if (p_dyndns->info[i].alias_count && /* exception for tunnelbroker.net - no name to lookup */ strcmp(p_dyndns->info[i].p_dns_system->p_key, "*****@*****.**")) { /* DNS Lookup */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ if (!(s = getaddrinfo(p_dyndns->info[i].alias_info[0].names.name, NULL, &hints, &result))) { /* DNS reply for alias found, convert to IP# */ if (!getnameinfo(result->ai_addr, result->ai_addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) { /* Update local record for next checkip call. */ strncpy(p_dyndns->info[i].my_ip_address.name, name, sizeof(p_dyndns->info[i].my_ip_address.name)); logit(LOG_INFO, MODULE_TAG "Resolving hostname %s => IP# %s", p_dyndns->info[i].alias_info[0].names.name, name); } freeaddrinfo(result); } else logit(LOG_WARNING, MODULE_TAG "Failed resolving hostname %s: %s", p_dyndns->info[i].alias_info[0].names.name, gai_strerror(s)); } } } else { /* Read cached IP# from inadyn cache file. */ if (fgets(name, sizeof(name), fp)) { logit(LOG_INFO, MODULE_TAG "Cached IP# %s from previous invocation.", name); /* Update local record for next checkip call. */ for (i = 0; i < p_dyndns->info_count; i++) { strncpy(p_dyndns->info[i].my_ip_address.name, name, sizeof(p_dyndns->info[i].my_ip_address.name)); } } fclose(fp); } do { rc = dyn_dns_init(p_dyndns); if (rc != RC_OK) { break; } rc = get_encoded_user_passwd(p_dyndns); if (rc != RC_OK) { break; } /* DDNS client main loop */ while (1) { rc = dyn_dns_update_ip(p_dyndns); if (rc != RC_OK) { if (p_dyndns->cmd == CMD_RESTART) { logit(LOG_DEBUG, "RESTART command received. Restarting."); rc = RC_RESTART; break; } if (rc == RC_DYNDNS_RSP_NOTOK && p_dyndns->total_iterations == 1) { logit(LOG_ERR, MODULE_TAG "Error response from DDNS server, exiting!"); break; } iterations_err++; } else { /* count only the successful iterations */ p_dyndns->num_iterations++; iterations_err = 0; } /* check if the user wants us to stop */ if (p_dyndns->total_iterations != 0 && p_dyndns->num_iterations >= p_dyndns->total_iterations) { break; } if (p_dyndns->total_iterations != 1) { if (rc == RC_DYNDNS_RSP_RETRY_LATER || rc == RC_DYNDNS_RSP_NOTOK) p_dyndns->sleep_sec = p_dyndns->error_update_period_sec; else p_dyndns->sleep_sec = p_dyndns->normal_update_period_sec; } else p_dyndns->sleep_sec = DYNDNS_MIN_SLEEP; if (rc != RC_OK) { /* dyn_dns_update_ip() failed above, and we've not reached MAX iterations. * Time to inform the user the (network) error is not fatal and that we * will try again in a short while. */ logit(LOG_WARNING, MODULE_TAG "Will retry again in %d sec...", p_dyndns->sleep_sec); } /* Now sleep a while. Using the time set in sleep_sec data member */ dyn_dns_wait_for_cmd(p_dyndns); if (p_dyndns->cmd == CMD_STOP) { logit(LOG_DEBUG, MODULE_TAG "STOP command received, exiting."); rc = RC_OK; break; } else if (p_dyndns->cmd == CMD_RESTART) { if (p_dyndns->dbg.level > 0) logit(LOG_DEBUG, "RESTART command received, restarting."); rc = RC_RESTART; break; } if (p_dyndns->total_iterations > 0 && iterations_err > p_dyndns->total_iterations) { rc = RC_OK; break; } if (p_dyndns->dbg.level > 0) { logit(LOG_DEBUG, "."); // logit(LOG_DEBUG, "Time since last update: %d", p_dyndns->time_since_last_update); } p_dyndns->time_since_last_update += p_dyndns->sleep_sec; } } while (0); /* if everything ok here we should exit. End of program */ if (rc == RC_OK) { rc = dyn_dns_shutdown(p_dyndns); } return rc; }
/** MAIN - Dyn DNS update entry point Actions: - read the configuration options - perform various init actions as specified in the options - create and init dyn_dns object. - launch the IP update action loop */ int dyn_dns_main(ddns_t *ctx, int argc, char *argv[]) { FILE *fp; int rc = 0; int i, s; char name[DYNDNS_SERVER_NAME_LEN]; static int first_startup = 1; if (!ctx) return RC_INVALID_POINTER; /* Create pid and cache file repository. */ mkdir(DYNDNS_RUNTIME_DATA_DIR, 0755); /* read cmd line options and set object properties */ rc = get_config_data(ctx, argc, argv); if (rc != 0 || ctx->abort) return rc; if (ctx->change_persona) { ddns_user_t user; memset(&user, 0, sizeof(user)); user.gid = ctx->sys_usr_info.gid; user.uid = ctx->sys_usr_info.uid; rc = os_change_persona(&user); if (rc != 0) return rc; } /* if logfile provided, redirect output to log file */ if (strlen(ctx->dbg.p_logfilename) != 0) { rc = os_open_dbg_output(DBG_FILE_LOG, "", ctx->dbg.p_logfilename); if (rc != 0) { return rc; } } if (ctx->debug_to_syslog == 1 || (ctx->run_in_background == 1)) { if (get_dbg_dest() == DBG_STD_LOG) { /* avoid file and syslog output */ rc = os_open_dbg_output(DBG_SYS_LOG, "inadyn", NULL); if (rc != 0) { return rc; } } } /* if silent required, close console window */ if (ctx->run_in_background == 1) { rc = close_console_window(); if (rc != 0) { return rc; } if (get_dbg_dest() == DBG_SYS_LOG) { fclose(stdout); } } /* Create files with permissions 0644 */ umask(S_IWGRP | S_IWOTH); /* write pid file */ fp = fopen(ctx->pidfile, "w"); if (!fp) { logit(LOG_ERR, "Failed opening pidfile %s for writing: %s", ctx->pidfile, strerror(errno)); return RC_ERROR; } fprintf(fp, "%u\n", getpid()); fclose(fp); /* "Hello!" Let user know we've started up OK */ logit(LOG_INFO, "%s", DYNDNS_VERSION_STRING); /* On first startup only, optionally wait for network and any NTP daemon * to set system time correctly. Intended for devices without battery * backed real time clocks as initialization of time since last update * requires the correct time. Sleep can be cancelled with any signal, * but it is recommended to use SIGUSR1. */ if (first_startup && ctx->startup_delay_sec) { logit(LOG_NOTICE, "Startup delay: %d sec ...", ctx->startup_delay_sec); os_sleep_ms(1000 * ctx->startup_delay_sec); first_startup = 0; } /* At boot, or when restarting inadyn at runtime, the memory struct holding * our current IP# is empty. We want to avoid unnecessary updates of our * DDNS server record, since we might get locked out for abuse, so we "seed" * each of the DDNS records of our struct with the cached IP# from our cache * file, or from a regular DNS query. */ fp = fopen(ctx->cache_file, "r"); if (!fp) { struct addrinfo hints; struct addrinfo *result; /* Clear DNS cache before querying for the IP below. */ res_init(); /* Try a DNS lookup of our last known IP#. */ for (i = 0; i < ctx->info_count; i++) { if (ctx->info[i].alias_count && /* exception for tunnelbroker.net - no name to lookup */ strcmp(ctx->info[i].system->key, "*****@*****.**")) { /* DNS Lookup */ memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_INET; /* IPv4 */ hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ hints.ai_flags = 0; hints.ai_protocol = 0; /* Any protocol */ if (!(s = getaddrinfo(ctx->info[i].alias[0].names.name, NULL, &hints, &result))) { /* DNS reply for alias found, convert to IP# */ if (!getnameinfo (result->ai_addr, result->ai_addrlen, name, sizeof(name), NULL, 0, NI_NUMERICHOST)) { /* Update local record for next checkip call. */ strncpy(ctx->info[i].my_ip_address.name, name, sizeof(ctx->info[i].my_ip_address.name)); logit(LOG_INFO, "Resolving hostname %s => IP# %s", ctx->info[i].alias[0].names.name, name); } freeaddrinfo(result); } else { logit(LOG_WARNING, "Failed resolving hostname %s: %s", ctx->info[i].alias[0].names.name, gai_strerror(s)); } } } } else { struct stat statbuf; /* Read cached IP# from inadyn cache file. */ if (fgets(name, sizeof(name), fp)) { logit(LOG_INFO, "Cached IP# %s from previous invocation.", name); /* Update local record for next checkip call. */ for (i = 0; i < ctx->info_count; i++) { strncpy(ctx->info[i].my_ip_address.name, name, sizeof(ctx->info[i].my_ip_address.name)); } } /* Initialize time since last update from modification time of cache file. */ if (fstat(fileno(fp), &statbuf) == 0) { time_t now = time(NULL); if (now != -1 && now > statbuf.st_mtime) { cached_time_since_last_update = (int)(now - statbuf.st_mtime); logit(LOG_INFO, "Cached time since last update %d (seconds) from previous invocation.", cached_time_since_last_update); } } fclose(fp); } do { rc = dyn_dns_init(ctx); if (rc != 0) break; rc = get_encoded_user_passwd(ctx); if (rc != 0) break; if (ctx->update_once == 1) ctx->force_addr_update = 1; /* DDNS client main loop */ while (1) { rc = dyn_dns_update_ip(ctx); if (rc != 0) { if (ctx->cmd == CMD_RESTART) { logit(LOG_INFO, "RESTART command received. Restarting."); rc = RC_RESTART; ctx->cmd = NO_CMD; break; } if (rc == RC_DYNDNS_RSP_NOTOK) { logit(LOG_ERR, "Error response from DDNS server, exiting!"); break; } } else { /* count only the successful iterations */ ctx->num_iterations++; } /* check if the user wants us to stop */ if (ctx->total_iterations != 0 && ctx->num_iterations >= ctx->total_iterations) break; ctx->sleep_sec = rc == RC_DYNDNS_RSP_RETRY_LATER ? ctx->error_update_period_sec : ctx->normal_update_period_sec; if (rc != 0) { /* dyn_dns_update_ip() failed above, and we've not reached MAX iterations. * Time to inform the user the (network) error is not fatal and that we * will try again in a short while. */ logit(LOG_WARNING, "Will retry again in %d sec...", ctx->sleep_sec); } /* Now sleep a while. Using the time set in sleep_sec data member */ dyn_dns_wait_for_cmd(ctx); if (ctx->cmd == CMD_STOP) { logit(LOG_INFO, "STOP command received, exiting."); rc = 0; ctx->cmd = NO_CMD; break; } if (ctx->cmd == CMD_RESTART) { logit(LOG_INFO, "RESTART command received, restarting."); rc = RC_RESTART; ctx->cmd = NO_CMD; break; } if (ctx->cmd == CMD_FORCED_UPDATE) { logit(LOG_INFO, "FORCED_UPDATE command received, updating now."); ctx->force_addr_update = 1; ctx->cmd = NO_CMD; continue; } if (ctx->dbg.level > 0) { logit(LOG_DEBUG, "."); // logit(LOG_DEBUG, "Time since last update: %d", ctx->time_since_last_update); } ctx->time_since_last_update += ctx->sleep_sec; } /* Save old value, if restarted by SIGHUP */ cached_time_since_last_update = ctx->time_since_last_update; cached_num_iterations = ctx->num_iterations; } while (0); /* if everything ok here we should exit. End of program */ if (rc == 0) rc = dyn_dns_shutdown(ctx); return rc; }
/* Actions: - read the configuration options - perform various init actions as specified in the options - create and init dyn_dns object. - launch the IP update action loop */ int dyn_dns_main(DYN_DNS_CLIENT *p_dyndns, int argc, char* argv[]) { RC_TYPE rc = RC_OK; int iterations = 0; BOOL quit_flag = FALSE; BOOL init_flag; BOOL os_handler_installed = FALSE; FILE *fp; if (p_dyndns == NULL) { return RC_INVALID_POINTER; } /* read cmd line options and set object properties*/ rc = get_config_data(p_dyndns, argc, argv); if (rc != RC_OK || p_dyndns->abort) { return rc; } /*if logfile provided, redirect output to log file*/ if (strlen(p_dyndns->dbg.p_logfilename) != 0) { rc = os_open_dbg_output(DBG_FILE_LOG, "", p_dyndns->dbg.p_logfilename); if (rc != RC_OK) { return rc; } } if (p_dyndns->debug_to_syslog == TRUE || (p_dyndns->run_in_background == TRUE)) { if (get_dbg_dest() == DBG_STD_LOG) /*avoid file and syslog output */ { rc = os_open_dbg_output(DBG_SYS_LOG, "INADYN", NULL); if (rc != RC_OK) { return rc; } } } if (p_dyndns->change_persona) { OS_USER_INFO os_usr_info; memset(&os_usr_info, 0, sizeof(os_usr_info)); os_usr_info.gid = p_dyndns->sys_usr_info.gid; os_usr_info.uid = p_dyndns->sys_usr_info.uid; rc = os_change_persona(&os_usr_info); if (rc != RC_OK) { return rc; } } /*if silent required, close console window*/ if (p_dyndns->run_in_background == TRUE) { rc = close_console_window(); if (rc != RC_OK) { return rc; } if (get_dbg_dest() == DBG_SYS_LOG) { fclose(stdout); } } dyn_dns_print_hello(NULL); if ((fp=fopen(p_dyndns->ip_cache, "r"))) { fgets (p_dyndns->info.my_ip_address.name, sizeof (p_dyndns->info.my_ip_address.name),fp); fclose(fp); DBG_PRINTF((LOG_INFO, MODULE_TAG "IP read from cache file is '%s'. No update required.\n", p_dyndns->info.my_ip_address.name)); } /* the real work here */ do { /* init object */ init_flag = FALSE; rc = dyn_dns_init(p_dyndns); if (rc != RC_OK) { break; } init_flag = TRUE; rc = get_encoded_user_passwd(p_dyndns); if (rc != RC_OK) { break; } if (!os_handler_installed) { rc = os_install_signal_handler(p_dyndns); if (rc != RC_OK) { DBG_PRINTF((LOG_WARNING,"DYNDNS: Error '%s' (0x%x) installing OS signal handler\n", errorcode_get_name(rc), rc)); break; } os_handler_installed = TRUE; } /*update IP address in a loop*/ while(1) { rc = dyn_dns_update_ip(p_dyndns); if (rc != RC_OK) { DBG_PRINTF((LOG_WARNING,"W:'%s' (0x%x) updating the IPs. (it %d)\n", errorcode_get_name(rc), rc, iterations)); } /* check if the user wants us to stop */ ++iterations; if (iterations >= p_dyndns->total_iterations && p_dyndns->total_iterations != 0) { break; } p_dyndns->sleep_sec = rc == RC_DYNDNS_RSP_RETRY_LATER ? DYNDNS_ERROR_UPDATE_PERIOD : DYNDNS_DEFAULT_SLEEP; /* also sleep the time set in the ->sleep_sec data memeber*/ dyn_dns_wait_for_cmd(p_dyndns); if (p_dyndns->cmd == CMD_STOP) { DBG_PRINTF((LOG_DEBUG,"STOP command received. Exiting.\n")); rc = RC_OK; break; } if (rc == RC_OK) { if (p_dyndns->dbg.level > 0) { DBG_PRINTF((LOG_DEBUG,".")); } p_dyndns->times_since_last_update ++; } else { dyn_dns_shutdown(p_dyndns); init_flag = FALSE; break; } } /*if everything ok here we should exit. End of program*/ if (rc == RC_OK) { break; } } while(quit_flag == FALSE); if (init_flag == TRUE) { /* dyn_dns_shutdown object */ rc = dyn_dns_shutdown(p_dyndns); } return rc; }
/** MAIN - Dyn DNS update entry point Actions: - read the configuration options - perform various init actions as specified in the options - create and init dyn_dns object. - launch the IP update action loop */ int dyn_dns_main(DYN_DNS_CLIENT *p_dyndns, int argc, char* argv[]) { RC_TYPE rc = RC_OK; int iterations = 0; BOOL os_handler_installed = FALSE; if (p_dyndns == NULL) { return RC_INVALID_POINTER; } /* read cmd line options and set object properties*/ rc = get_config_data(p_dyndns, argc, argv); if (rc != RC_OK || p_dyndns->abort) { return rc; } /*if logfile provided, redirect output to log file*/ if (strlen(p_dyndns->dbg.p_logfilename) != 0) { rc = os_open_dbg_output(DBG_FILE_LOG, "", p_dyndns->dbg.p_logfilename); if (rc != RC_OK) { return rc; } } if (p_dyndns->debug_to_syslog == TRUE || (p_dyndns->run_in_background == TRUE)) { if (get_dbg_dest() == DBG_STD_LOG) /*avoid file and syslog output */ { rc = os_open_dbg_output(DBG_SYS_LOG, "INADYN", NULL); if (rc != RC_OK) { return rc; } } } if (p_dyndns->change_persona) { OS_USER_INFO os_usr_info; memset(&os_usr_info, 0, sizeof(os_usr_info)); os_usr_info.gid = p_dyndns->sys_usr_info.gid; os_usr_info.uid = p_dyndns->sys_usr_info.uid; rc = os_change_persona(&os_usr_info); if (rc != RC_OK) { return rc; } } /*if silent required, close console window*/ if (p_dyndns->run_in_background == TRUE) { rc = close_console_window(); if (rc != RC_OK) { return rc; } if (get_dbg_dest() == DBG_SYS_LOG) { fclose(stdout); } } dyn_dns_print_hello(NULL); /* the real work here */ do { /* init object */ rc = dyn_dns_init(p_dyndns); if (rc != RC_OK) { break; } rc = get_encoded_user_passwd(p_dyndns); if (rc != RC_OK) { break; } if (!os_handler_installed) { rc = os_install_signal_handler(p_dyndns); if (rc != RC_OK) { DBG_PRINTF((LOG_WARNING,"DYNDNS: Error '%s' (0x%x) installing OS signal handler\n", errorcode_get_name(rc), rc)); break; } os_handler_installed = TRUE; } /*update IP address in a loop*/ while(1) { rc = dyn_dns_update_ip(p_dyndns); if (rc != RC_OK) { DBG_PRINTF((LOG_WARNING,"W:'%s' (0x%x) updating the IPs. (it %d)\n", errorcode_get_name(rc), rc, iterations)); if (rc == RC_DYNDNS_RSP_NOTOK) { DBG_PRINTF((LOG_ERR,"E: The response of DYNDNS svr was an error! Aborting.\n")); break; } } else /*count only the successful iterations */ { ++iterations; } /* check if the user wants us to stop */ if (iterations >= p_dyndns->total_iterations && p_dyndns->total_iterations != 0) { break; } /* also sleep the time set in the ->sleep_sec data memeber*/ dyn_dns_wait_for_cmd(p_dyndns); if (p_dyndns->cmd == CMD_STOP) { DBG_PRINTF((LOG_DEBUG,"STOP command received. Exiting.\n")); rc = RC_OK; break; } if (rc == RC_OK) { if (p_dyndns->dbg.level > 0) { DBG_PRINTF((LOG_DEBUG,".")); } p_dyndns->times_since_last_update ++; } } } while(FALSE); return rc; }