/// Function to enable listening to a particular ethernet multicast address. /// This is a highly non-portable function. /// I wonder how you do this on BSD or Slowlaris? FSTATIC gboolean _enable_mcast_address(const char * addrstring ///<[in] multicast MAC address string suitable for giving to 'ip' , const char * dev ///<[in] ethernet device , gboolean enable) ///<[in] TRUE to enable, FALSE to disable { GSpawnFlags flags = G_SPAWN_STDOUT_TO_DEV_NULL | G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_SEARCH_PATH; gint exit_status; const gchar* constargv [] = {"ip", "maddress", (enable ? "add" : "delete"), addrstring, "dev", dev, NULL}; gchar* argv[DIMOF(constargv)]; unsigned j; if (NULL == addrstring) { return FALSE; } // This is really stupid and annoying - they have the wrong function prototype for g_spawn_sync... for (j=0; j < DIMOF(argv); ++j) { argv[j] = g_strdup(constargv[j]); } DEBUGMSG1("Running IP command %s %s %s %s %s %s", argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); if (!g_spawn_sync(NULL, argv, NULL, flags, NULL, NULL, NULL, NULL, &exit_status, NULL)) { exit_status = 300; } for (j=0; j < DIMOF(argv); ++j) { g_free(argv[j]); argv[j] = NULL; } DEBUGMSG1("Previous IP command returned %d", exit_status); return exit_status == 0; }
/// Unregister all discovery methods in preparation for shutting down - to make valgrind happy :-D void discovery_unregister_all(void) { if (_discovery_timers != NULL) { GHashTable* timers = _discovery_timers; _discovery_timers = NULL; g_hash_table_remove_all(timers); g_hash_table_destroy(timers); timers = NULL; }else{ DEBUGMSG1("Discovery timers were NULL"); } }
/// Create a persistent keypair and write it to disk /// Returns a MALLOCed string with the key id for the key pair. Please free! WINEXPORT char * cryptcurve25519_gen_persistent_keypair(const char * giveitaname) ///< giveitaname can be NULL { unsigned char* public_key = g_malloc(crypto_box_PUBLICKEYBYTES); unsigned char* secret_key = g_malloc(crypto_box_SECRETKEYBYTES); char* key_id; char* sysname; // This is to try and keep our dummy array from being optimized out // so that we get stack protection, and clang doesn't complain... crypto_box_keypair(public_key, secret_key); if (NULL == giveitaname) { char* checksum_string; // Then we'll generate one based on host name and key's checksum checksum_string = cryptcurve25519_naming_checksum(public_key, crypto_box_PUBLICKEYBYTES); sysname = proj_get_sysname(); key_id = g_strdup_printf("%s@@%s", sysname, checksum_string); g_free(sysname); g_free(checksum_string); } else { key_id = g_strdup(giveitaname); } DEBUGMSG1("%s.%d: Generating permanent key pair [%s]", __FUNCTION__, __LINE__, key_id); // Write out the two generated keys (the key-pair) into the correct names if (!_cryptcurve25519_save_a_key(key_id, PUBLICKEY, public_key) || !_cryptcurve25519_save_a_key(key_id, PRIVATEKEY, secret_key) || cryptframe_privatekey_new(key_id, secret_key) == NULL || cryptframe_publickey_new(key_id, public_key) == NULL) { // Something didn't work :-( cryptcurve25519_purge_keypair(key_id); g_free(public_key); public_key = NULL; g_free(secret_key); secret_key = NULL; g_free(key_id); key_id = NULL; return NULL; } _cache_curve25519_keypair(key_id); return key_id; }
/// Save a curve25519 key to a file. FSTATIC gboolean _cryptcurve25519_save_a_key(const char * key_id,///<[in] key_id to save enum keytype ktype, ///<[in] type of key being saved gconstpointer key) ///<[in] pointer to key { ssize_t keysize; guint32 createmode; int fd; int rc; char* filename; if (!_is_legal_curve25519_key_id(key_id)) { g_warning("%s.%d: Key id %s is illegal", __FUNCTION__, __LINE__, key_id); return FALSE; } filename = curve25519_key_id_to_filename(key_id, ktype); if (PUBLICKEY == ktype) { keysize = crypto_box_PUBLICKEYBYTES; createmode = 0644; }else if (PRIVATEKEY == ktype) { keysize = crypto_box_SECRETKEYBYTES; createmode = 0600; }else{ g_error("%s.%d: Key type %d is illegal", __FUNCTION__, __LINE__, ktype); g_return_val_if_reached(FALSE); } // If it's a public key, it may exist but not be writable by us... if (PUBLICKEY == ktype && g_access(filename, R_OK) == 0) { // So, let's check and see if it's what we think it should be... if (_cache_curve25519_keypair(key_id)) { CryptFramePublicKey* pub = cryptframe_public_key_by_id(key_id); if (pub && memcmp(pub->public_key, key, keysize) == 0) { FREE(filename); filename = NULL; return TRUE; } } } fd = open(filename, O_WRONLY|O_CREAT, createmode); if (fd < 0 && (ENOENT == errno)) { char* dirname = _cache_curve25519_key_id_to_dirname(key_id, ktype); _cryptcurve25519_make_cryptdir(dirname); FREE(dirname); fd = open(filename, O_WRONLY|O_CREAT, createmode); } if (fd < 0) { g_warning("%s.%d: cannot create file %s [%s]", __FUNCTION__, __LINE__ , filename, g_strerror(errno)); g_free(filename); return FALSE; } DEBUGMSG4("Saving key to file %s", filename); DEBUGCKSUM4("Saved key:", key, keysize); rc = write(fd, key, keysize); if (rc != keysize) { g_warning("%s.%d: cannot write file %s: rc=%d [%s]", __FUNCTION__, __LINE__ , filename, rc, g_strerror(errno)); close(fd); g_unlink(filename); g_free(filename); return FALSE; } if (close(fd) < 0) { g_warning("%s.%d: Close of file %s failed.", __FUNCTION__, __LINE__, filename); g_unlink(filename); g_free(filename); return FALSE; } chmod(filename, createmode); // Ignore umask... DEBUGMSG1("%s.%d: file %s successfully created!", __FUNCTION__, __LINE__, filename); g_free(filename); return TRUE; }
/** * Set up pcap listener for the given interfaces and protocols. * @return a properly configured pcap_t* object for listening for the given protocols - NULL on error * @see pcap_protocols */ pcap_t* create_pcap_listener(const char * dev ///<[in] Device name to listen on , gboolean blocking ///<[in] TRUE if this is a blocking connection , unsigned listenmask ///<[in] Bit mask of protocols to listen for ///< (see @ref pcap_protocols "list of valid bits") , struct bpf_program*prog) ///<[out] Compiled PCAP program { pcap_t* pcdescr = NULL; bpf_u_int32 maskp = 0; bpf_u_int32 netp = 0; char errbuf[PCAP_ERRBUF_SIZE]; char * expr = NULL; int filterlen = 1; unsigned j; int cnt=0; int rc; const char ORWORD [] = " or "; gboolean need_promisc = FALSE; BINDDEBUG(pcap_t); // setbuf(stdout, NULL); setvbuf(stdout, NULL, _IONBF, 0); errbuf[0] = '\0'; // Search the list of valid bits so we can construct the libpcap filter // for the given set of protocols on the fly... // On this pass we just compute the amount of memory we'll need... for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { ++cnt; if (cnt > 1) { filterlen += sizeof(ORWORD); } filterlen += strlen(filterinfo[j].filter); } } if (filterlen < 2) { g_warning("Constructed filter is too short - invalid mask argument."); return NULL; } if (NULL == (expr = malloc(filterlen))) { g_error("Out of memory!"); return NULL; } // Same song, different verse... // This time around, we construct the filter expr[0] = '\0'; for (j = 0, cnt = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { ++cnt; if (cnt > 1) { g_strlcat(expr, ORWORD, filterlen); } g_strlcat(expr, filterinfo[j].filter, filterlen); } } if (pcap_lookupnet(dev, &netp, &maskp, errbuf) != 0) { // This is not a problem for non-IPv4 protocols... // It just looks up the ipv4 address - which we mostly don't care about. g_info("%s.%d: pcap_lookupnet(\"%s\") failed: [%s]" , __FUNCTION__, __LINE__, dev, errbuf); } if (NULL == (pcdescr = pcap_create(dev, errbuf))) { g_warning("pcap_create failed: [%s]", errbuf); goto oopsie; } //pcap_set_promisc(pcdescr, FALSE); for (j = 0; j < DIMOF(filterinfo); ++j) { if (listenmask & filterinfo[j].filterbit) { const char * addrstring = filterinfo[j].mcastaddr; if (addrstring && !_enable_mcast_address(addrstring, dev, TRUE)) { need_promisc = TRUE; } } } pcap_set_promisc(pcdescr, need_promisc); #ifdef HAVE_PCAP_SET_RFMON pcap_set_rfmon(pcdescr, FALSE); #endif pcap_setdirection(pcdescr, PCAP_D_IN); // Weird bug - returns -3 and doesn't show an error message... // And pcap_getnonblock also returns -3... Neither should happen AFAIK... errbuf[0] = '\0'; if ((rc = pcap_setnonblock(pcdescr, !blocking, errbuf)) < 0 && errbuf[0] != '\0') { g_warning("pcap_setnonblock(%d) failed: [%s] [rc=%d]", !blocking, errbuf, rc); g_warning("Have no idea why this happens - current blocking state is: %d." , pcap_getnonblock(pcdescr, errbuf)); } pcap_set_snaplen(pcdescr, 1500); /// @todo deal with pcap_set_timeout() call here. if (blocking) { pcap_set_timeout(pcdescr, 240*1000); } else { pcap_set_timeout(pcdescr, 1); } //pcap_set_buffer_size(pcdescr, 1500); if (pcap_activate(pcdescr) != 0) { g_warning("pcap_activate failed: [%s]", pcap_geterr(pcdescr)); goto oopsie; } if (pcap_compile(pcdescr, prog, expr, FALSE, maskp) < 0) { g_warning("pcap_compile of [%s] failed: [%s]", expr, pcap_geterr(pcdescr)); goto oopsie; } if (pcap_setfilter(pcdescr, prog) < 0) { g_warning("pcap_setfilter on [%s] failed: [%s]", expr, pcap_geterr(pcdescr)); goto oopsie; } DEBUGMSG1("Compile of [%s] worked!", expr); free(expr); expr = NULL; return(pcdescr); oopsie: // Some kind of failure - free things up and return NULL g_warning("%s.%d: Could not set up PCAP on %s" , __FUNCTION__, __LINE__, dev); if (expr) { free(expr); expr = NULL; } if (pcdescr) { close_pcap_listener(pcdescr, dev, listenmask); pcdescr = NULL; } return NULL; }
/// Called when an operation completes - it calls requestor's callback if no repeat, /// and requeues it if it is going to repeat FSTATIC void _resource_queue_endnotify ( ConfigContext* request , gpointer user_data , enum HowDied exittype , int rc , int signal , gboolean core_dumped , const char* stringresult) { RscQElem* self = CASTTOCLASS(RscQElem, user_data); ResourceQueue* parent = self->parent; ResourceCmd* cmd = self->cmd; gboolean shouldrepeat = TRUE; g_queue_remove(self->ourQ, self); parent->activechildcnt -= 1; if (parent->shuttingdown && parent->activechildcnt <= 0) { _resource_queue_finalize(&parent->baseclass); return; } DEBUGMSG1("%s.%d: EXIT happened exittype:%d repeat:%d, cancelme:%d", __FUNCTION__, __LINE__ , exittype, self->repeatinterval, self->cancelme); // Should this request repeat? if (self->cancelme || (self->cancelonfail && exittype != EXITED_ZERO) || (0 == self->repeatinterval)) { shouldrepeat = FALSE; }else{ shouldrepeat = TRUE; } // Notify the user that their repeating command flipped status, or has stopped running // (i.e., if it was failing but now works, or was working, but now fails) if (FALSE == shouldrepeat || (exittype == EXITED_ZERO && !cmd->last_success) || (exittype != EXITED_ZERO && cmd->last_success)) { DEBUGMSG1("%s.%d: Calling callback for request id " FMT_64BIT "d." , __FUNCTION__, __LINE__, self->requestid); self->callback(request, self->user_data, exittype, rc, signal, core_dumped , stringresult); if (shouldrepeat && exittype == EXITED_ZERO && stringresult) { g_message("%s: %s", cmd->loggingname, stringresult); } } cmd->last_success = (exittype == EXITED_ZERO); if (shouldrepeat) { DEBUGMSG1("%s.%d: Repeat request id " FMT_64BIT "d.", __FUNCTION__, __LINE__ , self->requestid); self->queuetime = g_get_monotonic_time(); cmd->starttime = self->queuetime + (self->repeatinterval*uSPERSEC); g_queue_push_tail(self->ourQ, self); _resource_queue_runqueue(self->parent); }else{ DEBUGMSG1("%s.%d: Don't repeat request id " FMT_64BIT "d.", __FUNCTION__, __LINE__ , self->requestid); if (g_queue_get_length(self->ourQ) == 0) { g_hash_table_remove(self->parent->resources, cmd->resourcename); } _resource_queue_runqueue(self->parent); _resource_queue_qelem_finalize(self); self = NULL; } // Undo the ref we did before starting this job UNREF(parent); }