static void _tgenio_deregister(TGenIO* io, gint descriptor) { TGEN_ASSERT(io); gint result = epoll_ctl(io->epollD, EPOLL_CTL_DEL, descriptor, NULL); if(result != 0) { tgen_warning("epoll_ctl(): epoll %i descriptor %i returned %i error %i: %s", io->epollD, descriptor, result, errno, g_strerror(errno)); } g_hash_table_remove(io->children, &descriptor); }
static void _tgenio_helper(TGenIO* io, TGenIOChild* child, gboolean in, gboolean out) { TGEN_ASSERT(io); g_assert(child); TGenEvent inEvents = TGEN_EVENT_NONE; /* check if we need read flag */ if(in) { tgen_debug("descriptor %i is readable", child->descriptor); inEvents |= TGEN_EVENT_READ; } /* check if we need write flag */ if(out) { tgen_debug("descriptor %i is writable", child->descriptor); inEvents |= TGEN_EVENT_WRITE; } /* activate the transfer */ TGenEvent outEvents = child->notify(child->data, child->descriptor, inEvents); /* now check if we should update our epoll events */ if(outEvents & TGEN_EVENT_DONE) { _tgenio_deregister(io, child->descriptor); } else if(inEvents != outEvents) { guint32 newEvents = 0; if(outEvents & TGEN_EVENT_READ) { newEvents |= EPOLLIN; } if(outEvents & TGEN_EVENT_WRITE) { newEvents |= EPOLLOUT; } struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.events = newEvents; ee.data.fd = child->descriptor; gint result = epoll_ctl(io->epollD, EPOLL_CTL_MOD, child->descriptor, &ee); if(result != 0) { tgen_warning("epoll_ctl(): epoll %i descriptor %i returned %i error %i: %s", io->epollD, child->descriptor, result, errno, g_strerror(errno)); } } }
static gint _tgenmain_run(gint argc, gchar *argv[]) { tgenLogFunc = _tgenmain_log; tgenLogFilterLevel = G_LOG_LEVEL_MESSAGE; /* get our hostname for logging */ gchar hostname[128]; memset(hostname, 0, 128); gethostname(hostname, 128); /* default to message level log until we read config */ tgen_message("Initializing traffic generator on host %s process id %i", hostname, (gint)getpid()); // TODO embedding a tgen graphml inside the shadow.config.xml file not yet supported // if(argv[1] && g_str_has_prefix(argv[1], "<?xml")) { // /* argv contains the xml contents of the xml file */ // gchar* tempPath = _tgendriver_makeTempFile(); // GError* error = NULL; // gboolean success = g_file_set_contents(tempPath, argv[1], -1, &error); // if(success) { // graph = tgengraph_new(tempPath); // } else { // tgen_warning("error (%i) while generating temporary xml file: %s", error->code, error->message); // } // g_unlink(tempPath); // g_free(tempPath); // } else { // /* argv contains the apth of a graphml config file */ // graph = tgengraph_new(argv[1]); // } /* argv[0] is program name, argv[1] should be config file */ if (argc != 2) { tgen_warning("USAGE: %s path/to/tgen.xml", argv[0]); tgen_critical("cannot continue: incorrect argument list format") return -1; }
static GError* _tgengraph_parseGraphEdges(TGenGraph* g) { TGEN_ASSERT(g); tgen_debug("checking graph edges..."); /* we will iterate through the edges */ igraph_eit_t edgeIterator; gint result = igraph_eit_create(g->graph, igraph_ess_all(IGRAPH_EDGEORDER_ID), &edgeIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_eit_create return non-success code %i", result); } /* count the edges as we iterate */ igraph_integer_t edgeCount = 0; GError* error = NULL; while (!IGRAPH_EIT_END(edgeIterator)) { igraph_integer_t edgeIndex = IGRAPH_EIT_GET(edgeIterator); igraph_integer_t fromVertexIndex, toVertexIndex; gint result = igraph_edge(g->graph, edgeIndex, &fromVertexIndex, &toVertexIndex); if(result != IGRAPH_SUCCESS) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_edge return non-success code %i", result); break; } const gchar* fromIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", fromVertexIndex) : NULL; if(!fromIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)fromVertexIndex); break; } const gchar* toIDStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", toVertexIndex) : NULL; if(!toIDStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing 'id' attribute", (glong)toVertexIndex); break; } tgen_debug("found edge %li from vertex %li (%s) to vertex %li (%s)", (glong)edgeIndex, (glong)fromVertexIndex, fromIDStr, (glong)toVertexIndex, toIDStr); const gchar* weightStr = (g->knownAttributes&TGEN_EA_WEIGHT) ? EAS(g->graph, "weight", edgeIndex) : NULL; if(weightStr != NULL) { if(g_ascii_strncasecmp(weightStr, "\0", (gsize) 1)) { gdouble weight = g_ascii_strtod(weightStr, NULL); _tgengraph_storeWeight(g, weight, edgeIndex); } } edgeCount++; IGRAPH_EIT_NEXT(edgeIterator); } igraph_eit_destroy(&edgeIterator); if(!error) { g->edgeCount = igraph_ecount(g->graph); if(g->edgeCount != edgeCount) { tgen_warning("igraph_vcount %f does not match iterator count %f", g->edgeCount, edgeCount); } tgen_info("%u graph edges ok", (guint) g->edgeCount); } return error; }
static GError* _tgengraph_parseGraphVertices(TGenGraph* g) { TGEN_ASSERT(g); tgen_debug("checking graph vertices..."); /* we will iterate through the vertices */ igraph_vit_t vertexIterator; gint result = igraph_vit_create(g->graph, igraph_vss_all(), &vertexIterator); if(result != IGRAPH_SUCCESS) { return g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_PARSE, "igraph_vit_create return non-success code %i", result); } /* count the vertices as we iterate */ igraph_integer_t vertexCount = 0; GError* error = NULL; while (!IGRAPH_VIT_END(vertexIterator)) { igraph_integer_t vertexIndex = (igraph_integer_t)IGRAPH_VIT_GET(vertexIterator); /* get vertex attributes: S for string and N for numeric */ const gchar* idStr = (g->knownAttributes&TGEN_VA_ID) ? VAS(g->graph, "id", vertexIndex) : NULL; if(!idStr) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_MISSING_ATTRIBUTE, "found vertex %li with missing action 'id' attribute", (glong)vertexIndex); break; } if(g_strstr_len(idStr, (gssize)-1, "start")) { error = _tgengraph_parseStartVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "end")) { error = _tgengraph_parseEndVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "pause")) { error = _tgengraph_parsePauseVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "synchronize")) { error = _tgengraph_parseSynchronizeVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "transfer")) { error = _tgengraph_parseTransferVertex(g, idStr, vertexIndex); } else if(g_strstr_len(idStr, (gssize)-1, "choose")) { error = _tgengraph_parseChooseVertex(g, idStr, vertexIndex); } else { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ELEMENT, "found vertex %li (%s) with an unknown action id '%s'", (glong)vertexIndex, idStr, idStr); } if(error) { break; } vertexCount++; IGRAPH_VIT_NEXT(vertexIterator); } /* clean up */ igraph_vit_destroy(&vertexIterator); if(!g->startHasPeers && g->transferMissingPeers) { error = g_error_new(G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, "peers required in either the 'start' action, or *every* 'transfer' action"); } if(!error) { g->vertexCount = igraph_vcount(g->graph); if(g->vertexCount != vertexCount) { tgen_warning("igraph_vcount %f does not match iterator count %f", g->vertexCount, vertexCount); } tgen_info("%u graph vertices ok", (guint) g->vertexCount); } return error; }
static TGenEvent _tgentransport_receiveSocksResponse(TGenTransport* transport) { /* 4 socks response client <-- server \x05 (version 5) \x00 (request granted) \x00 (reserved) the server can tell us that we need to reconnect elsewhere 4a ip address client <-- server \x01 (ipv4) in_addr_t (4 bytes) in_port_t (2 bytes) 4b hostname client <-- server \x03 (domain name) \x__ (1 byte name len) (name) in_port_t (2 bytes) */ gchar buffer[256]; memset(buffer, 0, 256); gssize bytesReceived = tgentransport_read(transport, buffer, 256); g_assert(bytesReceived >= 4); transport->time.proxyResponse = g_get_monotonic_time(); if(buffer[0] == 0x05 && buffer[1] == 0x00) { if(buffer[3] == 0x01) { /* case 4a - IPV4 mode - get address server told us */ g_assert(bytesReceived == 10); /* check if they want us to connect elsewhere */ in_addr_t socksBindAddress = 0; in_port_t socksBindPort = 0; g_memmove(&socksBindAddress, &buffer[4], 4); g_memmove(&socksBindPort, &buffer[8], 2); /* reconnect not supported */ if(socksBindAddress == 0 && socksBindPort == 0) { tgen_info("connection from %s through socks proxy %s to %s successful", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_SUCCESS); return TGEN_EVENT_DONE; } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_RECONN); tgen_warning("connection from %s through socks proxy %s to %s failed: " "proxy requested unsupported reconnection to %i:u", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (gint)socksBindAddress, (guint)ntohs(socksBindPort)); } } else if (buffer[3] == 0x03) { /* case 4b - domain name mode */ guint8 nameLength = 0; g_memmove(&nameLength, &buffer[4], 1); g_assert(bytesReceived == nameLength+7); gchar namebuf[nameLength+1]; memset(namebuf, 0, nameLength); in_port_t socksBindPort = 0; g_memmove(namebuf, &buffer[5], nameLength); g_memmove(&socksBindPort, &buffer[5+nameLength], 2); /* reconnect not supported */ if(!g_ascii_strncasecmp(namebuf, "\0", (gsize) 1) && socksBindPort == 0) { tgen_info("connection from %s through socks proxy %s to %s successful", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_SUCCESS); return TGEN_EVENT_DONE; } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_RECONN); tgen_warning("connection from %s through socks proxy %s to %s failed: " "proxy requested unsupported reconnection to %s:u", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), namebuf, (guint)ntohs(socksBindPort)); } } else { _tgentransport_changeError(transport, TGEN_XPORT_ERR_PROXY_ADDR); tgen_warning("connection from %s through socks proxy %s to %s failed: unsupported address type %i", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (gint)buffer[3]); } } else { _tgentransport_changeError(transport, (buffer[0] != 0x05) ? TGEN_XPORT_ERR_PROXY_VERSION : TGEN_XPORT_ERR_PROXY_STATUS); tgen_warning("connection from %s through socks proxy %s to %s failed: unsupported %s %i", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote), (buffer[0] != 0x05) ? "version" : "status", (buffer[0] != 0x05) ? (gint)buffer[0] : (gint)buffer[1]); } _tgentransport_changeState(transport, TGEN_XPORT_ERROR); return TGEN_EVENT_NONE; }
static TGenEvent _tgentransport_sendSocksRequest(TGenTransport* transport) { /* 3 socks request client --> server \x05 (version 5) \x01 (tcp stream) \x00 (reserved) the client asks the server to connect to a remote 3a ip address client --> server \x01 (ipv4) in_addr_t (4 bytes) in_port_t (2 bytes) 3b hostname client --> server \x03 (domain name) \x__ (1 byte name len) (name) in_port_t (2 bytes) */ /* prefer name mode if we have it, and let the proxy lookup IP as needed */ const gchar* name = tgenpeer_getName(transport->remote); if(name && g_str_has_suffix(name, ".onion")) { // FIXME remove suffix matching to have proxy do lookup for us /* case 3b - domain name */ glong nameLength = g_utf8_strlen(name, -1); guint8 guint8max = -1; if(nameLength > guint8max) { nameLength = (glong)guint8max; tgen_warning("truncated name '%s' in socks request from %i to %u bytes", name, nameLength, (guint)guint8max); } in_addr_t port = tgenpeer_getNetworkPort(transport->remote); gchar buffer[nameLength+8]; memset(buffer, 0, nameLength+8); g_memmove(&buffer[0], "\x05\x01\x00\x03", 4); g_memmove(&buffer[4], &nameLength, 1); g_memmove(&buffer[5], name, nameLength); g_memmove(&buffer[5+nameLength], &port, 2); gssize bytesSent = tgentransport_write(transport, buffer, nameLength+7); g_assert(bytesSent == nameLength+7); } else { tgenpeer_performLookups(transport->remote); // FIXME remove this to have proxy do lookup for us /* case 3a - IPv4 */ in_addr_t ip = tgenpeer_getNetworkIP(transport->remote); in_addr_t port = tgenpeer_getNetworkPort(transport->remote); gchar buffer[16]; memset(buffer, 0, 16); g_memmove(&buffer[0], "\x05\x01\x00\x01", 4); g_memmove(&buffer[4], &ip, 4); g_memmove(&buffer[8], &port, 2); gssize bytesSent = tgentransport_write(transport, buffer, 10); g_assert(bytesSent == 10); } transport->time.proxyRequest = g_get_monotonic_time(); tgen_debug("requested connection from %s through socks proxy %s to remote %s", tgenpeer_toString(transport->local), tgenpeer_toString(transport->proxy), tgenpeer_toString(transport->remote)); _tgentransport_changeState(transport, TGEN_XPORT_PROXY_RESPONSE); return TGEN_EVENT_READ; }