int main(int argc, char *argv[]) { FILE *f = stdin; char *rc_file = absolute_path(RC_FILE); char *hist_file = absolute_path(HIST_FILE); if (argc > 1) { /* On travaille sur un shell script: lui passer les arguments et le lancer */ add_program_parameters_environ(argc-1, argv+1); return execute_script(argv[1]); } else { /* Imprimer une bannière */ fprintf(stderr, "Bienvenue sur %s version %s\n", SHELL_NAME, VERSION); /* lancer éventuellement le script d'initialisation de l'utilisateur*/ if (access(rc_file, R_OK) == 0) execute_script(rc_file); /* Passer les paramètres (ici 0 param) et appeler le toplevel de l'interprete */ add_program_parameters_environ(1, argv); /* Gérer l'historique (la sauvegarde se fera automatiquement) */ init_history(HISTORY_DEFAULT_SIZE, hist_file); /* Lancement du toplevel de l'interprète */ toplevel(f); fprintf(stderr, "Bye\n"); } return EXIT_SUCCESS; }
int run_script_auto (struct incbin * incbin, const void * data, const char * script_file, FILE * out) { char ** script_lines = NULL; char * error = NULL; FILE * script = fopen(script_file, "r"); if (!script) goto error; script_lines = read_file_by_lines(script); fclose(script); char ** output_lines = execute_script(incbin, data, script_lines, &error); if (error) goto error; if (global_settings.insert_replacement_comment) write_header_comment(incbin, out); char ** line; char * indent; generate_initial_indented_line(&indent, NULL); for (line = output_lines; *line; line ++) { printf(">>>> %s%s\n", indent, *line); fprintf(out, "%s%s\n", indent, *line); } free(indent); destroy_string_array(output_lines); destroy_string_array(script_lines); return 0; error: destroy_string_array(script_lines); printf("err: %s\n", error); free(error); return 1; }
/* close all open network connections */ void close_network_connections(void) { avl_node_t *node, *next; connection_t *c; char *envp[5]; int i; for(node = connection_tree->head; node; node = next) { next = node->next; c = node->data; c->outgoing = NULL; terminate_connection(c, false); } for(list_node_t *node = outgoing_list->head; node; node = node->next) { outgoing_t *outgoing = node->data; if(outgoing->event) event_del(outgoing->event); } list_delete_list(outgoing_list); if(myself && myself->connection) { subnet_update(myself, NULL, false); terminate_connection(myself->connection, false); free_connection(myself->connection); } for(i = 0; i < listen_sockets; i++) { close(listen_socket[i].tcp); close(listen_socket[i].udp); } xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NAME=%s", myself->name); envp[4] = NULL; exit_requests(); exit_edges(); exit_subnets(); exit_nodes(); exit_connections(); exit_events(); execute_script("tinc-down", envp); if(myport) free(myport); for(i = 0; i < 4; i++) free(envp[i]); close_device(); return; }
void on_resize_bitmap(k3d::bitmap& Output) { k3d::iscript_engine::context context; context["document"] = &document(); context["node"] = static_cast<k3d::inode*>(this); context["output"] = &Output; execute_script(context); }
void* dealer_thread(){ request recived_request; int new_conn; pid_t son; printf("[Dealer]Politica:%s\n",policy); sem_wait(sem_full); sem_wait(sem_buffer); printf("[Schedule]%p\n",buffer); recived_request=buffer->request_list[0]; /*buffer->out++;*/ new_conn=recived_request.socket_id; printf("[Schedule]Recebi do Buffer:%d\n",recived_request.socket_id); sem_post(sem_buffer); sem_post(sem_empty); /* Process request*/ get_request(new_conn); /* Verify if request is for a page or script*/ if(!strncmp(req_buf,CGI_EXPR,strlen(CGI_EXPR))){ /*manda para um processo pelos pipes*/ if((son=fork())==0){ /*criar nova função para leitura de scripts e envior para a message queue*/ strcpy(recived_request.request_type,"dinamic"); strcpy(recived_request.request_file,req_buf); execute_script(new_conn); } waitpid(son,0,0); } else{ strcpy(recived_request.request_type,"static"); strcpy(recived_request.request_file,req_buf); pipe_write(0,recived_request); } sleep(20); // Terminate connection with client close(new_conn); printf("[Dealer]terminei serviço\n"); }
static void run_script(const char *scriptname) { char *envp[5]; int x; xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NAME=%s", myself->name); envp[4] = NULL; execute_script(scriptname, envp); for (x = 0; x < 4; x++) free(envp[x]); }
static bool finalize_invitation(connection_t *c, const char *data, uint16_t len) { if(strchr(data, '\n')) { logger(DEBUG_ALWAYS, LOG_ERR, "Received invalid key from invited node %s (%s)!\n", c->name, c->hostname); return false; } // Create a new host config file char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, c->name); if(!access(filename, F_OK)) { logger(DEBUG_ALWAYS, LOG_ERR, "Host config file for %s (%s) already exists!\n", c->name, c->hostname); return false; } FILE *f = fopen(filename, "w"); if(!f) { logger(DEBUG_ALWAYS, LOG_ERR, "Error trying to create %s: %s\n", filename, strerror(errno)); return false; } fprintf(f, "Ed25519PublicKey = %s\n", data); fclose(f); logger(DEBUG_CONNECTIONS, LOG_INFO, "Key succesfully received from %s (%s)", c->name, c->hostname); // Call invitation-accepted script char *envp[7] = {NULL}; char *address, *port; xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NODE=%s", c->name); sockaddr2str(&c->address, &address, &port); xasprintf(&envp[4], "REMOTEADDRESS=%s", address); xasprintf(&envp[5], "NAME=%s", myself->name); execute_script("invitation-accepted", envp); for(int i = 0; envp[i] && i < 7; i++) free(envp[i]); sptps_send_record(&c->sptps, 2, data, 0); return true; }
void on_update_color(k3d::color& Output) { k3d::iscript_engine::context context; context["document"] = &document(); context["node"] = static_cast<k3d::inode*>(this); context["output"] = k3d::color(1, 1, 1); execute_script(context); if(context["output"].type() == typeid(k3d::color)) { Output = boost::any_cast<k3d::color>(context["output"]); return; } k3d::log() << error << "unsupported output type: " << k3d::demangle(context["output"].type()) << std::endl; Output = k3d::color(1, 1, 1); }
int run_script (struct incbin * incbin, const void * data, FILE * out) { printf("Script file: "); char * script_name = read_line(stdin); if (!*script_name) { free(script_name); return 0; } FILE * script = fopen(script_name, "r"); free(script_name); if (!script) { printf("err: could not open script file\n"); return 0; } char ** script_lines = read_file_by_lines(script); fclose(script); char * error = NULL; char ** output_lines = execute_script(incbin, data, script_lines, &error); destroy_string_array(script_lines); return handle_script_output(output_lines, error, incbin, out); }
int main(int argc, const char** argv) { int res = -1; // Call the glue first. wasm_llvm_init(); res = execute_script(); if (res == -1) { return EXIT_SUCCESS; fprintf(stderr, "Executed script, success\n"); } else { fprintf(stderr, "Executed script, failure for assertion line %d\n", res); if (argc < 2) { fprintf(stderr, "No information on file used\n"); } else { PrintLine(argv[1], res); } return EXIT_FAILURE; } }
k3d::bool_t execute(k3d::iscript_engine::context& Context) { return execute_script(Context); }
/****************************************************************************** * * * Function: node_process_command * * * * Purpose: process command received from a master node or php * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * ******************************************************************************/ int node_process_command(zbx_sock_t *sock, const char *data, struct zbx_json_parse *jp) { char *result = NULL, *send = NULL, tmp[64]; int nodeid = -1, next_nodeid, ret = FAIL; zbx_uint64_t scriptid, hostid; struct zbx_json j; zabbix_log(LOG_LEVEL_DEBUG, "In node_process_command()"); zbx_json_init(&j, ZBX_JSON_STAT_BUF_LEN); if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_NODEID, tmp, sizeof(tmp)) || FAIL == is_uint31(tmp, &nodeid)) { result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_NODEID); goto finish; } if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_SCRIPTID, tmp, sizeof(tmp)) || FAIL == is_uint64(tmp, &scriptid)) { result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_SCRIPTID); goto finish; } if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOSTID, tmp, sizeof(tmp)) || FAIL == is_uint64(tmp, &hostid)) { result = zbx_dsprintf(result, "Failed to parse command request tag: %s.", ZBX_PROTO_TAG_HOSTID); goto finish; } if (nodeid == CONFIG_NODEID) { if (SUCCEED == (ret = execute_script(scriptid, hostid, &result))) { zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_SUCCESS, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, ZBX_PROTO_TAG_DATA, result, ZBX_JSON_TYPE_STRING); send = j.buffer; } } else if (SUCCEED == get_next_point_to_node(CONFIG_NODEID, nodeid, &next_nodeid)) { zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Sending command for Node %d to Node %d", CONFIG_NODEID, nodeid, next_nodeid); if (SUCCEED == (ret = send_script(next_nodeid, data, &result))) send = result; } else result = zbx_dsprintf(result, "NODE %d: Unknown Node ID [%d].", CONFIG_NODEID, nodeid); finish: if (FAIL == ret) { zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, ZBX_PROTO_TAG_INFO, (NULL != result ? result : "Unknown error."), ZBX_JSON_TYPE_STRING); send = j.buffer; } alarm(CONFIG_TIMEOUT); if (SUCCEED != zbx_tcp_send_raw(sock, send)) { zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Error sending result of command to node %d", CONFIG_NODEID, nodeid); } else { zabbix_log(LOG_LEVEL_DEBUG, "NODE %d: Sending back command '%s' result '%s'", CONFIG_NODEID, data, send); } alarm(0); zbx_json_free(&j); zbx_free(result); return ret; }
void cli_handler(char *buf) { if(buf) { if(g_context.ttymode) { if(strncmp(buf, "~.", 2) == 0) { char prompt[PATH_MAX]; g_context.ttymode = 0; rl_callback_handler_remove(); snprintf(prompt, PATH_MAX, "%s> ", g_context.currpath); rl_callback_handler_install(prompt, cli_handler); } else if(g_context.outsock >= 0) { char b[1024]; snprintf(b, sizeof(b), "%s\n", buf); write(g_context.outsock, b, strlen(b)); } return; } while(isspace(*buf)) { buf++; } if(*buf == 0) { if(g_context.asmmode) { char prompt[PATH_MAX]; g_context.asmmode = 0; g_context.asmaddr = 0; rl_callback_handler_remove(); snprintf(prompt, PATH_MAX, "%s> ", g_context.currpath); rl_callback_handler_install(prompt, cli_handler); } return; } if(in_script()) { /* When a script is running only accept stop */ if(strcmp(buf, "stop") == 0) { close_script(); } return; } if(g_context.asmmode) { char cmd[1024]; /* Do assembler */ unsigned int opcode; if(asmAssemble(buf, g_context.asmaddr, &opcode) == 0) { sprintf(cmd, "pokew 0x%08X 0x%08X ", g_context.asmaddr, opcode); execute_line(cmd); } return; } add_history(buf); if(buf[0] == '!') { if(strncmp(&buf[1], "cd ", 3) == 0) { chdir(&buf[4]); } else { system(&buf[1]); } return; } else if(buf[0] == '@') { if(g_context.fssock >= 0) { (void) write(g_context.fssock, &buf[1], strlen(&buf[1])); } return; } else if(buf[0] == '%') { execute_script(&buf[1]); return; } execute_line(buf); } else { shutdown_app(); exit(0); } }
int main(int argc, char *argv[]) { int rv = -1; const char *device = NULL; const char *scriptname = NULL; // wait for socket if not there right away? int dowait = 0; terminal_init(); int i=1; while(i<argc && argv[i][0]=='-' && argv[i][1] != 0) { switch(argv[i][1]) { case '?': assert_single_char(argv[i]); usage(EXIT_SUCCESS); /* usage() exits already */ break; case 'd': assert_single_char(argv[i]); if (i < argc-1) { i++; device = argv[i]; log_info("main: device = %s\n", device); } else { log_error("-d requires <device> parameter\n"); exit(1); } break; case 'v': set_verbose(); break; case 't': trace = 1; break; case 'w': dowait = 1; break; default: log_error("Unknown command line option %s\n", argv[i]); usage(1); break; } i++; } // next parameter is the script name if (i >= argc) { log_error("Script name parameter missing!\n"); return -1; } scriptname = argv[i]; i++; registry_t *script = load_script_from_file(scriptname); if (script != NULL) { int sockfd = socket_open(device, dowait); if (sockfd >= 0) { rv = execute_script(sockfd, script); } } return rv; }
/****************************************************************************** * * * Function: node_process_command * * * * Purpose: process command received from a master node or php * * * * Parameters: * * * * Return value: SUCCEED - processed successfully * * FAIL - an error occurred * * * * Author: Alexander Vladishev * * * * Comments: * * * ******************************************************************************/ int node_process_command(zbx_sock_t *sock, const char *data, struct zbx_json_parse *jp) { char *result = NULL, *send, tmp[64]; const char *response; int nodeid, next_nodeid, ret = FAIL; zbx_uint64_t scriptid, hostid; struct zbx_json j; zabbix_log(LOG_LEVEL_DEBUG, "In node_process_command()"); if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_NODEID, tmp, sizeof(tmp))) return FAIL; nodeid = atoi(tmp); if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_SCRIPTID, tmp, sizeof(tmp))) return FAIL; ZBX_STR2UINT64(scriptid, tmp); if (SUCCEED != zbx_json_value_by_name(jp, ZBX_PROTO_TAG_HOSTID, tmp, sizeof(tmp))) return FAIL; ZBX_STR2UINT64(hostid, tmp); zbx_json_init(&j, 256); if (nodeid == CONFIG_NODEID) { ret = execute_script(scriptid, hostid, &result); response = (FAIL == ret) ? ZBX_PROTO_VALUE_FAILED : ZBX_PROTO_VALUE_SUCCESS; zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, response, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, ZBX_PROTO_TAG_VALUE, result, ZBX_JSON_TYPE_STRING); send = j.buffer; } else if (SUCCEED == get_next_point_to_node(CONFIG_NODEID, nodeid, &next_nodeid)) { zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Sending command for Node %d to Node %d", CONFIG_NODEID, nodeid, next_nodeid); if (FAIL == (ret = send_script(next_nodeid, data, &result))) { zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, ZBX_PROTO_TAG_VALUE, result, ZBX_JSON_TYPE_STRING); send = j.buffer; } else send = result; } else { result = zbx_dsprintf(result, "NODE %d: Unknown Node ID [%d]", CONFIG_NODEID, nodeid); zbx_json_addstring(&j, ZBX_PROTO_TAG_RESPONSE, ZBX_PROTO_VALUE_FAILED, ZBX_JSON_TYPE_STRING); zbx_json_addstring(&j, ZBX_PROTO_TAG_VALUE, result, ZBX_JSON_TYPE_STRING); send = j.buffer; } alarm(CONFIG_TIMEOUT); if (zbx_tcp_send_raw(sock, send) != SUCCEED) { zabbix_log(LOG_LEVEL_WARNING, "NODE %d: Error sending result of command to node %d", CONFIG_NODEID, nodeid); } alarm(0); zbx_json_free(&j); zbx_free(result); return SUCCEED; }
int cmd_invite(int argc, char *argv[]) { if(argc < 2) { fprintf(stderr, "Not enough arguments!\n"); return 1; } // Check validity of the new node's name if(!check_id(argv[1])) { fprintf(stderr, "Invalid name for node.\n"); return 1; } char *myname = get_my_name(true); if(!myname) return 1; // Ensure no host configuration file with that name exists char filename[PATH_MAX]; snprintf(filename, sizeof filename, "%s" SLASH "hosts" SLASH "%s", confbase, argv[1]); if(!access(filename, F_OK)) { fprintf(stderr, "A host config file for %s already exists!\n", argv[1]); return 1; } // If a daemon is running, ensure no other nodes know about this name bool found = false; if(connect_tincd(false)) { sendline(fd, "%d %d", CONTROL, REQ_DUMP_NODES); while(recvline(fd, line, sizeof line)) { char node[4096]; int code, req; if(sscanf(line, "%d %d %s", &code, &req, node) != 3) break; if(!strcmp(node, argv[1])) found = true; } if(found) { fprintf(stderr, "A node with name %s is already known!\n", argv[1]); return 1; } } snprintf(filename, sizeof filename, "%s" SLASH "invitations", confbase); if(mkdir(filename, 0700) && errno != EEXIST) { fprintf(stderr, "Could not create directory %s: %s\n", filename, strerror(errno)); return 1; } // Count the number of valid invitations, clean up old ones DIR *dir = opendir(filename); if(!dir) { fprintf(stderr, "Could not read directory %s: %s\n", filename, strerror(errno)); return 1; } errno = 0; int count = 0; struct dirent *ent; time_t deadline = time(NULL) - 604800; // 1 week in the past while((ent = readdir(dir))) { if(strlen(ent->d_name) != 24) continue; char invname[PATH_MAX]; struct stat st; snprintf(invname, sizeof invname, "%s" SLASH "%s", filename, ent->d_name); if(!stat(invname, &st)) { if(deadline < st.st_mtime) count++; else unlink(invname); } else { fprintf(stderr, "Could not stat %s: %s\n", invname, strerror(errno)); errno = 0; } } closedir(dir); if(errno) { fprintf(stderr, "Error while reading directory %s: %s\n", filename, strerror(errno)); return 1; } ecdsa_t *key; snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "ed25519_key.priv", confbase); // Remove the key if there are no outstanding invitations. if(!count) unlink(filename); // Create a new key if necessary. FILE *f = fopen(filename, "r"); if(!f) { if(errno != ENOENT) { fprintf(stderr, "Could not read %s: %s\n", filename, strerror(errno)); return 1; } key = ecdsa_generate(); if(!key) return 1; f = fopen(filename, "w"); if(!f) { fprintf(stderr, "Could not write %s: %s\n", filename, strerror(errno)); return 1; } chmod(filename, 0600); if(!ecdsa_write_pem_private_key(key, f)) { fprintf(stderr, "Could not write ECDSA private key\n"); fclose(f); return 1; } fclose(f); if(connect_tincd(false)) sendline(fd, "%d %d", CONTROL, REQ_RELOAD); } else { key = ecdsa_read_pem_private_key(f); fclose(f); if(!key) fprintf(stderr, "Could not read private key from %s\n", filename); } if(!key) return 1; // Create a hash of the key. char hash[64]; char *fingerprint = ecdsa_get_base64_public_key(key); sha512(fingerprint, strlen(fingerprint), hash); b64encode_urlsafe(hash, hash, 18); // Create a random cookie for this invitation. char cookie[25]; randomize(cookie, 18); // Create a filename that doesn't reveal the cookie itself char buf[18 + strlen(fingerprint)]; char cookiehash[64]; memcpy(buf, cookie, 18); memcpy(buf + 18, fingerprint, sizeof buf - 18); sha512(buf, sizeof buf, cookiehash); b64encode_urlsafe(cookiehash, cookiehash, 18); b64encode_urlsafe(cookie, cookie, 18); // Create a file containing the details of the invitation. snprintf(filename, sizeof filename, "%s" SLASH "invitations" SLASH "%s", confbase, cookiehash); int ifd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600); if(!ifd) { fprintf(stderr, "Could not create invitation file %s: %s\n", filename, strerror(errno)); return 1; } f = fdopen(ifd, "w"); if(!f) abort(); // Get the local address char *address = get_my_hostname(); // Fill in the details. fprintf(f, "Name = %s\n", argv[1]); if(netname) fprintf(f, "NetName = %s\n", netname); fprintf(f, "ConnectTo = %s\n", myname); // Copy Broadcast and Mode FILE *tc = fopen(tinc_conf, "r"); if(tc) { char buf[1024]; while(fgets(buf, sizeof buf, tc)) { if((!strncasecmp(buf, "Mode", 4) && strchr(" \t=", buf[4])) || (!strncasecmp(buf, "Broadcast", 9) && strchr(" \t=", buf[9]))) { fputs(buf, f); // Make sure there is a newline character. if(!strchr(buf, '\n')) fputc('\n', f); } } fclose(tc); } fprintf(f, "#---------------------------------------------------------------#\n"); fprintf(f, "Name = %s\n", myname); char filename2[PATH_MAX]; snprintf(filename2, sizeof filename2, "%s" SLASH "hosts" SLASH "%s", confbase, myname); fcopy(f, filename2); fclose(f); // Create an URL from the local address, key hash and cookie char *url; xasprintf(&url, "%s/%s%s", address, hash, cookie); // Call the inviation-created script char *envp[6] = {}; xasprintf(&envp[0], "NAME=%s", myname); xasprintf(&envp[1], "NETNAME=%s", netname); xasprintf(&envp[2], "NODE=%s", argv[1]); xasprintf(&envp[3], "INVITATION_FILE=%s", filename); xasprintf(&envp[4], "INVITATION_URL=%s", url); execute_script("invitation-created", envp); for(int i = 0; i < 6 && envp[i]; i++) free(envp[i]); puts(url); free(url); free(address); return 0; }
/* Configure node_t myself and set up the local sockets (listen only) */ bool setup_myself(void) { config_t *cfg; subnet_t *subnet; char *name, *hostname, *mode, *afname, *cipher, *digest; char *fname = NULL; char *address = NULL; char *envp[5]; struct addrinfo *ai, *aip, hint = {0}; bool choice; int i, err; int replaywin_int; myself = new_node(); myself->connection = new_connection(); myself->hostname = xstrdup("MYSELF"); myself->connection->hostname = xstrdup("MYSELF"); myself->connection->options = 0; myself->connection->protocol_version = PROT_CURRENT; if(!get_config_string(lookup_config(config_tree, "Name"), &name)) { /* Not acceptable */ logger(LOG_ERR, "Name for tinc daemon required!"); return false; } if(!check_id(name)) { logger(LOG_ERR, "Invalid name for myself!"); free(name); return false; } myself->name = name; myself->connection->name = xstrdup(name); xasprintf(&fname, "%s/hosts/%s", confbase, name); read_config_options(config_tree, name); read_config_file(config_tree, fname); free(fname); if(!read_rsa_private_key()) return false; if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) myport = xstrdup("655"); if(!atoi(myport)) { struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); sockaddr_t sa; if(!ai || !ai->ai_addr) return false; free(myport); memcpy(&sa, ai->ai_addr, ai->ai_addrlen); sockaddr2str(&sa, NULL, &myport); } /* Read in all the subnets specified in the host configuration file */ cfg = lookup_config(config_tree, "Subnet"); while(cfg) { if(!get_config_subnet(cfg, &subnet)) return false; subnet_add(myself, subnet); cfg = lookup_config_next(config_tree, cfg); } /* Check some options */ if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) myself->options |= OPTION_INDIRECT; if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) myself->options |= OPTION_TCPONLY; if(myself->options & OPTION_TCPONLY) myself->options |= OPTION_INDIRECT; get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets); get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver); strictsubnets |= tunnelserver; if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) { if(!strcasecmp(mode, "router")) routing_mode = RMODE_ROUTER; else if(!strcasecmp(mode, "switch")) routing_mode = RMODE_SWITCH; else if(!strcasecmp(mode, "hub")) routing_mode = RMODE_HUB; else { logger(LOG_ERR, "Invalid routing mode!"); return false; } free(mode); } if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { if(!strcasecmp(mode, "off")) forwarding_mode = FMODE_OFF; else if(!strcasecmp(mode, "internal")) forwarding_mode = FMODE_INTERNAL; else if(!strcasecmp(mode, "kernel")) forwarding_mode = FMODE_KERNEL; else { logger(LOG_ERR, "Invalid forwarding mode!"); return false; } free(mode); } choice = true; get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice); if(choice) myself->options |= OPTION_PMTU_DISCOVERY; choice = true; get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice); if(choice) myself->options |= OPTION_CLAMP_MSS; get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); #if !defined(SOL_IP) || !defined(IP_TOS) if(priorityinheritance) logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance"); #endif if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) macexpire = 600; if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) { if(maxtimeout <= 0) { logger(LOG_ERR, "Bogus maximum timeout!"); return false; } } else maxtimeout = 900; if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { if(udp_rcvbuf <= 0) { logger(LOG_ERR, "UDPRcvBuf cannot be negative!"); return false; } } if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) { if(udp_sndbuf <= 0) { logger(LOG_ERR, "UDPSndBuf cannot be negative!"); return false; } } if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) { if(replaywin_int < 0) { logger(LOG_ERR, "ReplayWindow cannot be negative!"); return false; } replaywin = (unsigned)replaywin_int; } if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) { if(!strcasecmp(afname, "IPv4")) addressfamily = AF_INET; else if(!strcasecmp(afname, "IPv6")) addressfamily = AF_INET6; else if(!strcasecmp(afname, "any")) addressfamily = AF_UNSPEC; else { logger(LOG_ERR, "Invalid address family!"); return false; } free(afname); } get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames); /* Generate packet encryption key */ if(get_config_string (lookup_config(config_tree, "Cipher"), &cipher)) { if(!strcasecmp(cipher, "none")) { myself->incipher = NULL; } else { myself->incipher = EVP_get_cipherbyname(cipher); if(!myself->incipher) { logger(LOG_ERR, "Unrecognized cipher type!"); return false; } } } else myself->incipher = EVP_bf_cbc(); if(myself->incipher) myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; else myself->inkeylength = 1; myself->connection->outcipher = EVP_bf_ofb(); if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; keyexpires = now + keylifetime; /* Check if we want to use message authentication codes... */ if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) { if(!strcasecmp(digest, "none")) { myself->indigest = NULL; } else { myself->indigest = EVP_get_digestbyname(digest); if(!myself->indigest) { logger(LOG_ERR, "Unrecognized digest type!"); return false; } } } else myself->indigest = EVP_sha1(); myself->connection->outdigest = EVP_sha1(); if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) { if(myself->indigest) { if(myself->inmaclength > myself->indigest->md_size) { logger(LOG_ERR, "MAC length exceeds size of digest!"); return false; } else if(myself->inmaclength < 0) { logger(LOG_ERR, "Bogus MAC length!"); return false; } } } else myself->inmaclength = 4; myself->connection->outmaclength = 0; /* Compression */ if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) { if(myself->incompression < 0 || myself->incompression > 11) { logger(LOG_ERR, "Bogus compression level!"); return false; } } else myself->incompression = 0; myself->connection->outcompression = 0; /* Done */ myself->nexthop = myself; myself->via = myself; myself->status.reachable = true; node_add(myself); graph(); if(strictsubnets) load_all_subnets(); /* Open device */ if(!setup_device()) return false; /* Run tinc-up script to further initialize the tap interface */ xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NAME=%s", myself->name); envp[4] = NULL; execute_script("tinc-up", envp); for(i = 0; i < 5; i++) free(envp[i]); /* Run subnet-up scripts for our own subnets */ subnet_update(myself, NULL, true); /* Open sockets */ get_config_string(lookup_config(config_tree, "BindToAddress"), &address); hint.ai_family = addressfamily; hint.ai_socktype = SOCK_STREAM; hint.ai_protocol = IPPROTO_TCP; hint.ai_flags = AI_PASSIVE; err = getaddrinfo(address, myport, &hint, &ai); if(err || !ai) { logger(LOG_ERR, "System call `%s' failed: %s", "getaddrinfo", gai_strerror(err)); return false; } listen_sockets = 0; for(aip = ai; aip; aip = aip->ai_next) { listen_socket[listen_sockets].tcp = setup_listen_socket((sockaddr_t *) aip->ai_addr); if(listen_socket[listen_sockets].tcp < 0) continue; listen_socket[listen_sockets].udp = setup_vpn_in_socket((sockaddr_t *) aip->ai_addr); if(listen_socket[listen_sockets].udp < 0) continue; ifdebug(CONNECTIONS) { hostname = sockaddr2hostname((sockaddr_t *) aip->ai_addr); logger(LOG_NOTICE, "Listening on %s", hostname); free(hostname); } memcpy(&listen_socket[listen_sockets].sa, aip->ai_addr, aip->ai_addrlen); listen_sockets++; } freeaddrinfo(ai); if(listen_sockets) logger(LOG_NOTICE, "Ready"); else { logger(LOG_ERR, "Unable to create any listening socket!"); return false; } return true; }
// the constructor bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif, const char *macaddr, eth_rx_handler_t rxh, void *rxarg, char *script) { int flags; char filename[BX_PATHNAME_LEN]; if (strncmp (netif, "tap", 3) != 0) { BX_PANIC (("eth_tap: interface name (%s) must be tap0..tap15", netif)); } sprintf (filename, "/dev/%s", netif); #if defined(__linux__) // check if the TAP devices is running, and turn on ARP. This is based // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/ int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { BX_PANIC (("socket creation: %s", strerror(errno))); return; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name)); if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { BX_PANIC (("SIOCGIFFLAGS on %s: %s", netif, strerror(errno))); close(sock); return; } if (!(ifr.ifr_flags & IFF_RUNNING)) { BX_PANIC (("%s device is not running", netif)); close(sock); return; } if ((ifr.ifr_flags & IFF_NOARP)){ BX_INFO(("turn on ARP for %s device", netif)); ifr.ifr_flags &= ~IFF_NOARP; if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { BX_PANIC (("SIOCSIFFLAGS: %s", strerror(errno))); close(sock); return; } } close(sock); #endif fd = open (filename, O_RDWR); if (fd < 0) { BX_PANIC(("open failed on %s: %s", netif, strerror(errno))); return; } /* set O_ASYNC flag so that we can poll with read() */ if ((flags = fcntl(fd, F_GETFL)) < 0) { BX_PANIC(("getflags on tap device: %s", strerror(errno))); } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { BX_PANIC(("set tap device flags: %s", strerror(errno))); } BX_INFO(("eth_tap: opened %s device", netif)); /* Execute the configuration script */ char intname[IFNAMSIZ]; strcpy(intname,netif); if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0)) { if (execute_script(script, intname) < 0) BX_ERROR(("execute script '%s' on %s failed", script, intname)); } // Start the rx poll this->rx_timer_index = bx_pc_system.register_timer(this, this->rx_timer_handler, 1000, 1, 1, "eth_tap"); // continuous, active this->rxh = rxh; this->rxarg = rxarg; memcpy(&guest_macaddr[0], macaddr, 6); #if BX_ETH_TAP_LOGGING // eventually Bryce wants txlog to dump in pcap format so that // tcpdump -r FILE can read it and interpret packets. txlog = fopen ("ne2k-tx.log", "wb"); if (!txlog) BX_PANIC (("open ne2k-tx.log failed")); txlog_txt = fopen ("ne2k-txdump.txt", "wb"); if (!txlog_txt) BX_PANIC (("open ne2k-txdump.txt failed")); fprintf (txlog_txt, "tap packetmover readable log file\n"); fprintf (txlog_txt, "net IF = %s\n", netif); fprintf (txlog_txt, "MAC address = "); for (int i=0; i<6; i++) fprintf (txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : ""); fprintf (txlog_txt, "\n--\n"); fflush (txlog_txt); rxlog = fopen ("ne2k-rx.log", "wb"); if (!rxlog) BX_PANIC (("open ne2k-rx.log failed")); rxlog_txt = fopen ("ne2k-rxdump.txt", "wb"); if (!rxlog_txt) BX_PANIC (("open ne2k-rxdump.txt failed")); fprintf (rxlog_txt, "tap packetmover readable log file\n"); fprintf (rxlog_txt, "net IF = %s\n", netif); fprintf (rxlog_txt, "MAC address = "); for (int i=0; i<6; i++) fprintf (rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : ""); fprintf (rxlog_txt, "\n--\n"); fflush (rxlog_txt); #endif }
static void sssp_bfs(void) { avl_node_t *node, *next, *to; edge_t *e; node_t *n; list_t *todo_list; list_node_t *from, *todonext; bool indirect; char *name; char *address, *port; char *envp[7]; int i; todo_list = list_alloc(NULL); /* Clear visited status on nodes */ for(node = node_tree->head; node; node = node->next) { n = node->data; n->status.visited = false; n->status.indirect = true; } /* Begin with myself */ myself->status.visited = true; myself->status.indirect = false; myself->nexthop = myself; myself->prevedge = NULL; myself->via = myself; list_insert_head(todo_list, myself); /* Loop while todo_list is filled */ for(from = todo_list->head; from; from = todonext) { /* "from" is the node from which we start */ n = from->data; for(to = n->edge_tree->head; to; to = to->next) { /* "to" is the edge connected to "from" */ e = to->data; if(!e->reverse) continue; /* Situation: / / ----->(n)---e-->(e->to) \ \ Where e is an edge, (n) and (e->to) are nodes. n->address is set to the e->address of the edge left of n to n. We are currently examining the edge e right of n from n: - If edge e provides for better reachability of e->to, update e->to and (re)add it to the todo_list to (re)examine the reachability of nodes behind it. */ indirect = n->status.indirect || e->options & OPTION_INDIRECT; if(e->to->status.visited && (!e->to->status.indirect || indirect)) continue; e->to->status.visited = true; e->to->status.indirect = indirect; e->to->nexthop = (n->nexthop == myself) ? e->to : n->nexthop; e->to->prevedge = e; e->to->via = indirect ? n->via : e->to; e->to->options = e->options; if(e->to->address.sa.sa_family == AF_UNSPEC && e->address.sa.sa_family != AF_UNKNOWN) update_node_udp(e->to, &e->address); list_insert_tail(todo_list, e->to); } todonext = from->next; list_delete_node(todo_list, from); } list_free(todo_list); /* Check reachability status. */ for(node = node_tree->head; node; node = next) { next = node->next; n = node->data; if(n->status.visited != n->status.reachable) { n->status.reachable = !n->status.reachable; if(n->status.reachable) { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became reachable", n->name, n->hostname); } else { ifdebug(TRAFFIC) logger(LOG_DEBUG, "Node %s (%s) became unreachable", n->name, n->hostname); } /* TODO: only clear status.validkey if node is unreachable? */ n->status.validkey = false; n->last_req_key = 0; n->maxmtu = MTU; n->minmtu = 0; n->mtuprobes = 0; if(n->mtuevent) { event_del(n->mtuevent); n->mtuevent = NULL; } xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NODE=%s", n->name); sockaddr2str(&n->address, &address, &port); xasprintf(&envp[4], "REMOTEADDRESS=%s", address); xasprintf(&envp[5], "REMOTEPORT=%s", port); envp[6] = NULL; execute_script(n->status.reachable ? "host-up" : "host-down", envp); xasprintf(&name, n->status.reachable ? "hosts/%s-up" : "hosts/%s-down", n->name); execute_script(name, envp); free(name); free(address); free(port); for(i = 0; i < 6; i++) free(envp[i]); subnet_update(n, NULL, n->status.reachable); if(!n->status.reachable) update_node_udp(n, NULL); else if(n->connection) send_ans_key(n); } }
void subnet_update(node_t *owner, subnet_t *subnet, bool up) { avl_node_t *node; int i; char *envp[10] = {NULL}; char netstr[MAXNETSTR]; char *name, *address, *port; char empty[] = ""; // Prepare environment variables to be passed to the script xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NODE=%s", owner->name); if(owner != myself) { sockaddr2str(&owner->address, &address, &port); // 4 and 5 are reserved for SUBNET and WEIGHT xasprintf(&envp[6], "REMOTEADDRESS=%s", address); xasprintf(&envp[7], "REMOTEPORT=%s", port); free(port); free(address); } xasprintf(&envp[8], "NAME=%s", myself->name); name = up ? "subnet-up" : "subnet-down"; if(!subnet) { for(node = owner->subnet_tree->head; node; node = node->next) { subnet = node->data; if(!net2str(netstr, sizeof netstr, subnet)) continue; // Strip the weight from the subnet, and put it in its own environment variable char *weight = strchr(netstr, '#'); if(weight) *weight++ = 0; else weight = empty; // Prepare the SUBNET and WEIGHT variables if(envp[4]) free(envp[4]); if(envp[5]) free(envp[5]); xasprintf(&envp[4], "SUBNET=%s", netstr); xasprintf(&envp[5], "WEIGHT=%s", weight); execute_script(name, envp); } } else { if(net2str(netstr, sizeof netstr, subnet)) { // Strip the weight from the subnet, and put it in its own environment variable char *weight = strchr(netstr, '#'); if(weight) *weight++ = 0; else weight = empty; // Prepare the SUBNET and WEIGHT variables xasprintf(&envp[4], "SUBNET=%s", netstr); xasprintf(&envp[5], "WEIGHT=%s", weight); execute_script(name, envp); } } for(i = 0; envp[i] && i < 9; i++) free(envp[i]); }
// the constructor bx_tap_pktmover_c::bx_tap_pktmover_c(const char *netif, const char *macaddr, eth_rx_handler_t rxh, bx_devmodel_c *dev, const char *script) { int flags; char filename[BX_PATHNAME_LEN]; this->netdev = dev; if (strncmp (netif, "tap", 3) != 0) { BX_PANIC(("eth_tap: interface name (%s) must be tap0..tap15", netif)); } #if defined(__sun__) strcpy(filename,"/dev/tap"); /* PD - device on Solaris is always the same */ #else sprintf(filename, "/dev/%s", netif); #endif #if defined(__linux__) // check if the TAP devices is running, and turn on ARP. This is based // on code from the Mac-On-Linux project. http://http://www.maconlinux.org/ int sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { BX_PANIC(("socket creation: %s", strerror(errno))); return; } struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy(ifr.ifr_name, netif, sizeof(ifr.ifr_name)); if(ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) { BX_PANIC(("SIOCGIFFLAGS on %s: %s", netif, strerror(errno))); close(sock); return; } if (!(ifr.ifr_flags & IFF_RUNNING)) { BX_PANIC(("%s device is not running", netif)); close(sock); return; } if ((ifr.ifr_flags & IFF_NOARP)){ BX_INFO(("turn on ARP for %s device", netif)); ifr.ifr_flags &= ~IFF_NOARP; if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) { BX_PANIC(("SIOCSIFFLAGS: %s", strerror(errno))); close(sock); return; } } close(sock); #endif fd = open (filename, O_RDWR); if (fd < 0) { BX_PANIC(("open failed on TAP %s: %s", netif, strerror(errno))); return; } #if defined(__sun__) char *ptr; /* PD - ppa allocation ala qemu */ char my_dev[10]; /* enough ... */ int ppa=-1; struct strioctl strioc_ppa; my_dev[10-1]=0; strncpy(my_dev,netif,10); /* following ptr= does not work with const char* */ if( *my_dev ) { /* find the ppa number X from string tapX */ ptr = my_dev; while( *ptr && !isdigit((int)*ptr) ) ptr++; ppa = atoi(ptr); } /* Assign a new PPA and get its unit number. */ strioc_ppa.ic_cmd = TUNNEWPPA; strioc_ppa.ic_timout = 0; strioc_ppa.ic_len = sizeof(ppa); strioc_ppa.ic_dp = (char *)&ppa; if ((ppa = ioctl (fd, I_STR, &strioc_ppa)) < 0) BX_PANIC(("Can't assign new interface tap%d !",ppa)); #endif /* set O_ASYNC flag so that we can poll with read() */ if ((flags = fcntl(fd, F_GETFL)) < 0) { BX_PANIC(("getflags on tap device: %s", strerror(errno))); } flags |= O_NONBLOCK; if (fcntl(fd, F_SETFL, flags) < 0) { BX_PANIC(("set tap device flags: %s", strerror(errno))); } BX_INFO(("tap network drive: opened %s device", netif)); /* Execute the configuration script */ char intname[IFNAMSIZ]; strcpy(intname,netif); if((script != NULL) && (strcmp(script, "") != 0) && (strcmp(script, "none") != 0)) { if (execute_script(this->netdev, script, intname) < 0) BX_ERROR(("execute script '%s' on %s failed", script, intname)); } // Start the rx poll this->rx_timer_index = bx_pc_system.register_timer(this, this->rx_timer_handler, 1000, 1, 1, "eth_tap"); // continuous, active this->rxh = rxh; memcpy(&guest_macaddr[0], macaddr, 6); #if BX_ETH_TAP_LOGGING // eventually Bryce wants txlog to dump in pcap format so that // tcpdump -r FILE can read it and interpret packets. txlog = fopen("ne2k-tx.log", "wb"); if (!txlog) BX_PANIC(("open ne2k-tx.log failed")); txlog_txt = fopen("ne2k-txdump.txt", "wb"); if (!txlog_txt) BX_PANIC(("open ne2k-txdump.txt failed")); fprintf(txlog_txt, "tap packetmover readable log file\n"); fprintf(txlog_txt, "net IF = %s\n", netif); fprintf(txlog_txt, "MAC address = "); for (int i=0; i<6; i++) fprintf(txlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : ""); fprintf(txlog_txt, "\n--\n"); fflush(txlog_txt); rxlog = fopen("ne2k-rx.log", "wb"); if (!rxlog) BX_PANIC(("open ne2k-rx.log failed")); rxlog_txt = fopen("ne2k-rxdump.txt", "wb"); if (!rxlog_txt) BX_PANIC(("open ne2k-rxdump.txt failed")); fprintf(rxlog_txt, "tap packetmover readable log file\n"); fprintf(rxlog_txt, "net IF = %s\n", netif); fprintf(rxlog_txt, "MAC address = "); for (int i=0; i<6; i++) fprintf(rxlog_txt, "%02x%s", 0xff & macaddr[i], i<5?":" : ""); fprintf(rxlog_txt, "\n--\n"); fflush(rxlog_txt); #endif }
/* Configure node_t myself and set up the local sockets (listen only) */ static bool setup_myself(void) { config_t *cfg; subnet_t *subnet; char *name, *hostname, *mode, *afname, *cipher, *digest, *type; char *fname = NULL; char *address = NULL; char *proxy = NULL; char *space; char *envp[5] = {NULL}; struct addrinfo *ai, *aip, hint = {0}; bool choice; int i, err; int replaywin_int; bool port_specified = false; myself = new_node(); myself->connection = new_connection(); myself->hostname = xstrdup("MYSELF"); myself->connection->hostname = xstrdup("MYSELF"); myself->connection->options = 0; myself->connection->protocol_version = PROT_CURRENT; if(!(name = get_name())) { logger(LOG_ERR, "Name for tinc daemon required!"); return false; } /* Read tinc.conf and our own host config file */ myself->name = name; myself->connection->name = xstrdup(name); xasprintf(&fname, "%s/hosts/%s", confbase, name); read_config_options(config_tree, name); read_config_file(config_tree, fname); free(fname); if(!read_rsa_private_key()) return false; if(!get_config_string(lookup_config(config_tree, "Port"), &myport)) myport = xstrdup("655"); else port_specified = true; /* Ensure myport is numeric */ if(!atoi(myport)) { struct addrinfo *ai = str2addrinfo("localhost", myport, SOCK_DGRAM); sockaddr_t sa; if(!ai || !ai->ai_addr) return false; free(myport); memcpy(&sa, ai->ai_addr, ai->ai_addrlen); sockaddr2str(&sa, NULL, &myport); } get_config_string(lookup_config(config_tree, "Proxy"), &proxy); if(proxy) { if((space = strchr(proxy, ' '))) *space++ = 0; if(!strcasecmp(proxy, "none")) { proxytype = PROXY_NONE; } else if(!strcasecmp(proxy, "socks4")) { proxytype = PROXY_SOCKS4; } else if(!strcasecmp(proxy, "socks4a")) { proxytype = PROXY_SOCKS4A; } else if(!strcasecmp(proxy, "socks5")) { proxytype = PROXY_SOCKS5; } else if(!strcasecmp(proxy, "http")) { proxytype = PROXY_HTTP; } else if(!strcasecmp(proxy, "exec")) { proxytype = PROXY_EXEC; } else { logger(LOG_ERR, "Unknown proxy type %s!", proxy); return false; } switch(proxytype) { case PROXY_NONE: default: break; case PROXY_EXEC: if(!space || !*space) { logger(LOG_ERR, "Argument expected for proxy type exec!"); return false; } proxyhost = xstrdup(space); break; case PROXY_SOCKS4: case PROXY_SOCKS4A: case PROXY_SOCKS5: case PROXY_HTTP: proxyhost = space; if(space && (space = strchr(space, ' '))) *space++ = 0, proxyport = space; if(space && (space = strchr(space, ' '))) *space++ = 0, proxyuser = space; if(space && (space = strchr(space, ' '))) *space++ = 0, proxypass = space; if(!proxyhost || !*proxyhost || !proxyport || !*proxyport) { logger(LOG_ERR, "Host and port argument expected for proxy!"); return false; } proxyhost = xstrdup(proxyhost); proxyport = xstrdup(proxyport); if(proxyuser && *proxyuser) proxyuser = xstrdup(proxyuser); if(proxypass && *proxypass) proxypass = xstrdup(proxypass); break; } free(proxy); } /* Read in all the subnets specified in the host configuration file */ cfg = lookup_config(config_tree, "Subnet"); while(cfg) { if(!get_config_subnet(cfg, &subnet)) return false; subnet_add(myself, subnet); cfg = lookup_config_next(config_tree, cfg); } /* Check some options */ if(get_config_bool(lookup_config(config_tree, "IndirectData"), &choice) && choice) myself->options |= OPTION_INDIRECT; if(get_config_bool(lookup_config(config_tree, "TCPOnly"), &choice) && choice) myself->options |= OPTION_TCPONLY; if(myself->options & OPTION_TCPONLY) myself->options |= OPTION_INDIRECT; get_config_bool(lookup_config(config_tree, "DirectOnly"), &directonly); get_config_bool(lookup_config(config_tree, "StrictSubnets"), &strictsubnets); get_config_bool(lookup_config(config_tree, "TunnelServer"), &tunnelserver); get_config_bool(lookup_config(config_tree, "LocalDiscovery"), &localdiscovery); strictsubnets |= tunnelserver; if(get_config_string(lookup_config(config_tree, "Mode"), &mode)) { if(!strcasecmp(mode, "router")) routing_mode = RMODE_ROUTER; else if(!strcasecmp(mode, "switch")) routing_mode = RMODE_SWITCH; else if(!strcasecmp(mode, "hub")) routing_mode = RMODE_HUB; else { logger(LOG_ERR, "Invalid routing mode!"); return false; } free(mode); } if(get_config_string(lookup_config(config_tree, "Forwarding"), &mode)) { if(!strcasecmp(mode, "off")) forwarding_mode = FMODE_OFF; else if(!strcasecmp(mode, "internal")) forwarding_mode = FMODE_INTERNAL; else if(!strcasecmp(mode, "kernel")) forwarding_mode = FMODE_KERNEL; else { logger(LOG_ERR, "Invalid forwarding mode!"); return false; } free(mode); } choice = true; get_config_bool(lookup_config(config_tree, "PMTUDiscovery"), &choice); if(choice) myself->options |= OPTION_PMTU_DISCOVERY; choice = true; get_config_bool(lookup_config(config_tree, "ClampMSS"), &choice); if(choice) myself->options |= OPTION_CLAMP_MSS; get_config_bool(lookup_config(config_tree, "PriorityInheritance"), &priorityinheritance); get_config_bool(lookup_config(config_tree, "DecrementTTL"), &decrement_ttl); if(get_config_string(lookup_config(config_tree, "Broadcast"), &mode)) { if(!strcasecmp(mode, "no")) broadcast_mode = BMODE_NONE; else if(!strcasecmp(mode, "yes") || !strcasecmp(mode, "mst")) broadcast_mode = BMODE_MST; else if(!strcasecmp(mode, "direct")) broadcast_mode = BMODE_DIRECT; else { logger(LOG_ERR, "Invalid broadcast mode!"); return false; } free(mode); } #if !defined(SOL_IP) || !defined(IP_TOS) if(priorityinheritance) logger(LOG_WARNING, "%s not supported on this platform", "PriorityInheritance"); #endif if(!get_config_int(lookup_config(config_tree, "MACExpire"), &macexpire)) macexpire = 600; if(get_config_int(lookup_config(config_tree, "MaxTimeout"), &maxtimeout)) { if(maxtimeout <= 0) { logger(LOG_ERR, "Bogus maximum timeout!"); return false; } } else maxtimeout = 900; if(get_config_int(lookup_config(config_tree, "UDPRcvBuf"), &udp_rcvbuf)) { if(udp_rcvbuf <= 0) { logger(LOG_ERR, "UDPRcvBuf cannot be negative!"); return false; } } if(get_config_int(lookup_config(config_tree, "UDPSndBuf"), &udp_sndbuf)) { if(udp_sndbuf <= 0) { logger(LOG_ERR, "UDPSndBuf cannot be negative!"); return false; } } if(get_config_int(lookup_config(config_tree, "ReplayWindow"), &replaywin_int)) { if(replaywin_int < 0) { logger(LOG_ERR, "ReplayWindow cannot be negative!"); return false; } replaywin = (unsigned)replaywin_int; } if(get_config_string(lookup_config(config_tree, "AddressFamily"), &afname)) { if(!strcasecmp(afname, "IPv4")) addressfamily = AF_INET; else if(!strcasecmp(afname, "IPv6")) addressfamily = AF_INET6; else if(!strcasecmp(afname, "any")) addressfamily = AF_UNSPEC; else { logger(LOG_ERR, "Invalid address family!"); return false; } free(afname); } get_config_bool(lookup_config(config_tree, "Hostnames"), &hostnames); /* Generate packet encryption key */ if(get_config_string (lookup_config(config_tree, "Cipher"), &cipher)) { if(!strcasecmp(cipher, "none")) { myself->incipher = NULL; } else { myself->incipher = EVP_get_cipherbyname(cipher); if(!myself->incipher) { logger(LOG_ERR, "Unrecognized cipher type!"); return false; } } } else myself->incipher = EVP_bf_cbc(); if(myself->incipher) myself->inkeylength = myself->incipher->key_len + myself->incipher->iv_len; else myself->inkeylength = 1; myself->connection->outcipher = EVP_bf_ofb(); if(!get_config_int(lookup_config(config_tree, "KeyExpire"), &keylifetime)) keylifetime = 3600; keyexpires = now + keylifetime; /* Check if we want to use message authentication codes... */ if(get_config_string(lookup_config(config_tree, "Digest"), &digest)) { if(!strcasecmp(digest, "none")) { myself->indigest = NULL; } else { myself->indigest = EVP_get_digestbyname(digest); if(!myself->indigest) { logger(LOG_ERR, "Unrecognized digest type!"); return false; } } } else myself->indigest = EVP_sha1(); myself->connection->outdigest = EVP_sha1(); if(get_config_int(lookup_config(config_tree, "MACLength"), &myself->inmaclength)) { if(myself->indigest) { if(myself->inmaclength > myself->indigest->md_size) { logger(LOG_ERR, "MAC length exceeds size of digest!"); return false; } else if(myself->inmaclength < 0) { logger(LOG_ERR, "Bogus MAC length!"); return false; } } } else myself->inmaclength = 4; myself->connection->outmaclength = 0; /* Compression */ if(get_config_int(lookup_config(config_tree, "Compression"), &myself->incompression)) { if(myself->incompression < 0 || myself->incompression > 11) { logger(LOG_ERR, "Bogus compression level!"); return false; } } else myself->incompression = 0; myself->connection->outcompression = 0; /* Done */ myself->nexthop = myself; myself->via = myself; myself->status.reachable = true; node_add(myself); graph(); if(strictsubnets) load_all_subnets(); /* Open device */ devops = os_devops; if(get_config_string(lookup_config(config_tree, "DeviceType"), &type)) { if(!strcasecmp(type, "dummy")) devops = dummy_devops; else if(!strcasecmp(type, "raw_socket")) devops = raw_socket_devops; else if(!strcasecmp(type, "multicast")) devops = multicast_devops; #ifdef ENABLE_UML else if(!strcasecmp(type, "uml")) devops = uml_devops; #endif #ifdef ENABLE_VDE else if(!strcasecmp(type, "vde")) devops = vde_devops; #endif } if(!devops.setup()) return false; /* Run tinc-up script to further initialize the tap interface */ xasprintf(&envp[0], "NETNAME=%s", netname ? : ""); xasprintf(&envp[1], "DEVICE=%s", device ? : ""); xasprintf(&envp[2], "INTERFACE=%s", iface ? : ""); xasprintf(&envp[3], "NAME=%s", myself->name); execute_script("tinc-up", envp); for(i = 0; i < 4; i++) free(envp[i]); /* Run subnet-up scripts for our own subnets */ subnet_update(myself, NULL, true); /* Open sockets */ if(!do_detach && getenv("LISTEN_FDS")) { sockaddr_t sa; socklen_t salen; listen_sockets = atoi(getenv("LISTEN_FDS")); #ifdef HAVE_UNSETENV unsetenv("LISTEN_FDS"); #endif if(listen_sockets > MAXSOCKETS) { logger(LOG_ERR, "Too many listening sockets"); return false; } for(i = 0; i < listen_sockets; i++) { salen = sizeof sa; if(getsockname(i + 3, &sa.sa, &salen) < 0) { logger(LOG_ERR, "Could not get address of listen fd %d: %s", i + 3, sockstrerror(errno)); return false; } listen_socket[i].tcp = i + 3; #ifdef FD_CLOEXEC fcntl(i + 3, F_SETFD, FD_CLOEXEC); #endif listen_socket[i].udp = setup_vpn_in_socket(&sa); if(listen_socket[i].udp < 0) return false; ifdebug(CONNECTIONS) { hostname = sockaddr2hostname(&sa); logger(LOG_NOTICE, "Listening on %s", hostname); free(hostname); } memcpy(&listen_socket[i].sa, &sa, salen); } } else {