Пример #1
0
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);
}
Пример #2
0
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));
        }
    }
}
Пример #3
0
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;
    }
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}