Esempio n. 1
0
bool qd_policy_approve_amqp_session(pn_session_t *ssn, qd_connection_t *qd_conn)
{
    bool result = true;
    if (qd_conn->policy_settings) {
        if (qd_conn->policy_settings->maxSessions) {
            if (qd_conn->n_sessions == qd_conn->policy_settings->maxSessions) {
                qd_policy_deny_amqp_session(ssn, qd_conn);
                result = false;
            }
        }
    }
    pn_connection_t *conn = qd_connection_pn(qd_conn);
    qd_dispatch_t *qd = qd_conn->server->qd;
    qd_policy_t *policy = qd->policy;
    const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
    const char *app = pn_connection_remote_hostname(conn);
    if (result) {
        qd_log(policy->log_source,
           QD_LOG_TRACE,
           "ALLOW AMQP Begin Session. user: %s, hostip: %s, app: %s",
           qd_conn->user_id, hostip, app);
    } else {
        qd_log(policy->log_source,
           QD_LOG_INFO,
           "DENY AMQP Begin Session due to session limit. user: %s, hostip: %s, app: %s",
           qd_conn->user_id, hostip, app);
    }
    return result;
}
Esempio n. 2
0
qd_link_t *qd_link(qd_node_t *node, qd_connection_t *conn, qd_direction_t dir, const char* name)
{
    qd_link_t *link = new_qd_link_t();

    link->pn_sess = pn_session(qd_connection_pn(conn));
    pn_session_set_incoming_capacity(link->pn_sess, 1000000);

    if (dir == QD_OUTGOING)
        link->pn_link = pn_sender(link->pn_sess, name);
    else
        link->pn_link = pn_receiver(link->pn_sess, name);

    link->direction  = dir;
    link->context    = node->context;
    link->node       = node;
    link->drain_mode = pn_link_get_drain(link->pn_link);
    link->remote_snd_settle_mode = pn_link_remote_snd_settle_mode(link->pn_link);
    link->close_sess_with_link = true;

    //
    // Keep the borrowed references
    //
    pn_incref(link->pn_link);
    pn_incref(link->pn_sess);

    pn_link_set_context(link->pn_link, link);

    pn_session_open(link->pn_sess);

    return link;
}
Esempio n. 3
0
bool qd_policy_approve_amqp_receiver_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
{
    const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
    const char *app = pn_connection_remote_hostname(qd_connection_pn(qd_conn));

    if (qd_conn->policy_settings->maxReceivers) {
        if (qd_conn->n_receivers == qd_conn->policy_settings->maxReceivers) {
            // Max sender limit specified and violated.
            qd_log(qd_conn->server->qd->policy->log_source, QD_LOG_INFO,
                "DENY AMQP Attach receiver for user '%s', host '%s', app '%s' based on maxReceivers limit",
                qd_conn->user_id, hostip, app);
            _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
            return false;
        } else {
            // max receiver limit not violated
        }
    } else {
        // max receiver limit not specified
    }
    // Approve receiver link based on source
    bool dynamic_src = pn_terminus_is_dynamic(pn_link_remote_source(pn_link));
    if (dynamic_src) {
        bool lookup = qd_conn->policy_settings->allowDynamicSrc;
        qd_log(qd_conn->server->qd->policy->log_source, (lookup ? QD_LOG_TRACE : QD_LOG_INFO),
            "%s AMQP Attach receiver dynamic source for user '%s', host '%s', app '%s',",
            (lookup ? "ALLOW" : "DENY"), qd_conn->user_id, hostip, app);
        // Dynamic source policy rendered the decision
        if (!lookup) {
            _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
        }
        return lookup;
    }
    const char * source = pn_terminus_get_address(pn_link_remote_source(pn_link));
    if (source && *source) {
        // a source is specified
        bool lookup = _qd_policy_approve_link_name(qd_conn->user_id, qd_conn->policy_settings->sources, source);

        qd_log(qd_conn->server->qd->policy->log_source, (lookup ? QD_LOG_TRACE : QD_LOG_INFO),
            "%s AMQP Attach receiver link '%s' for user '%s', host '%s', app '%s' based on link source name",
            (lookup ? "ALLOW" : "DENY"), source, qd_conn->user_id, hostip, app);

        if (!lookup) {
            _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
            return false;
        }
    } else {
        // A receiver with no remote source.
        qd_log(qd_conn->server->qd->policy->log_source, QD_LOG_TRACE,
               "DENY AMQP Attach receiver link '' for user '%s', host '%s', app '%s'",
               qd_conn->user_id, hostip, app);
        _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
        return false;
    }
    // Approved
    return true;
}
Esempio n. 4
0
static void AMQP_opened_handler(qd_router_t *router, qd_connection_t *conn, bool inbound)
{
    qdr_connection_role_t  role = 0;
    int                    cost = 1;
    int                    remote_cost = 1;
    bool                   strip_annotations_in = false;
    bool                   strip_annotations_out = false;
    int                    link_capacity = 1;
    const char            *name = 0;
    uint64_t               connection_id = qd_connection_connection_id(conn);
    pn_connection_t       *pn_conn = qd_connection_pn(conn);

    qd_router_connection_get_config(conn, &role, &cost, &name,
                                    &strip_annotations_in, &strip_annotations_out, &link_capacity);

    if (role == QDR_ROLE_INTER_ROUTER) {
        //
        // Check the remote properties for an inter-router cost value.
        //
        pn_data_t *props = pn_conn ? pn_connection_remote_properties(pn_conn) : 0;
        if (props) {
            pn_data_rewind(props);
            pn_data_next(props);
            if (props && pn_data_type(props) == PN_MAP) {
                pn_data_enter(props);
                while (pn_data_next(props)) {
                    if (pn_data_type(props) == PN_SYMBOL) {
                        pn_bytes_t sym = pn_data_get_symbol(props);
                        if (sym.size == strlen(QD_CONNECTION_PROPERTY_COST_KEY) &&
                            strcmp(sym.start, QD_CONNECTION_PROPERTY_COST_KEY) == 0) {
                            pn_data_next(props);
                            if (pn_data_type(props) == PN_INT)
                                remote_cost = pn_data_get_int(props);
                            break;
                        }
                    }
                }
            }
        }

        //
        // Use the larger of the local and remote costs for this connection
        //
        if (remote_cost > cost)
            cost = remote_cost;
    }

    qdr_connection_t *qdrc = qdr_connection_opened(router->router_core, inbound, role, cost, connection_id, name,
                                                   pn_connection_remote_container(pn_conn),
                                                   strip_annotations_in, strip_annotations_out, link_capacity);

    qd_connection_set_context(conn, qdrc);
    qdr_connection_set_context(qdrc, conn);
}
Esempio n. 5
0
void qd_policy_amqp_open(void *context, bool discard)
{
    qd_connection_t *qd_conn = (qd_connection_t *)context;
    if (!discard) {
        pn_connection_t *conn = qd_connection_pn(qd_conn);
        qd_dispatch_t *qd = qd_conn->server->qd;
        qd_policy_t *policy = qd->policy;
        bool connection_allowed = true;

        if (policy->enableAccessRules) {
            // Open connection or not based on policy.
            pn_transport_t *pn_trans = pn_connection_transport(conn);
            const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
            const char *pcrh = pn_connection_remote_hostname(conn);
            const char *app = (pcrh ? pcrh : "");
            const char *conn_name = qdpn_connector_name(qd_conn->pn_cxtr);
#define SETTINGS_NAME_SIZE 256
            char settings_name[SETTINGS_NAME_SIZE];
            uint32_t conn_id = qd_conn->connection_id;
            qd_conn->policy_settings = NEW(qd_policy_settings_t); // TODO: memory pool for settings
            memset(qd_conn->policy_settings, 0, sizeof(qd_policy_settings_t));

            if (qd_policy_open_lookup_user(policy, qd_conn->user_id, hostip, app, conn_name,
                                           settings_name, SETTINGS_NAME_SIZE, conn_id,
                                           qd_conn->policy_settings) &&
                settings_name[0]) {
                // This connection is allowed by policy.
                // Apply transport policy settings
                if (qd_conn->policy_settings->maxFrameSize > 0)
                    pn_transport_set_max_frame(pn_trans, qd_conn->policy_settings->maxFrameSize);
                if (qd_conn->policy_settings->maxSessions > 0)
                    pn_transport_set_channel_max(pn_trans, qd_conn->policy_settings->maxSessions - 1);
            } else {
                // This connection is denied by policy.
                connection_allowed = false;
            }
        } else {
            // No policy implies automatic policy allow
            // Note that connections not governed by policy have no policy_settings.
        }
        if (connection_allowed) {
            if (pn_connection_state(conn) & PN_LOCAL_UNINIT)
                pn_connection_open(conn);
            policy_notify_opened(qd_conn->open_container, qd_conn, qd_conn->context);
        } else {
            qd_policy_private_deny_amqp_connection(conn, RESOURCE_LIMIT_EXCEEDED, CONNECTION_DISALLOWED);
        }
    }
    qd_connection_set_event_stall(qd_conn, false);
}
Esempio n. 6
0
bool qd_policy_approve_amqp_sender_link(pn_link_t *pn_link, qd_connection_t *qd_conn)
{
    const char *hostip = qdpn_connector_hostip(qd_conn->pn_cxtr);
    const char *app = pn_connection_remote_hostname(qd_connection_pn(qd_conn));

    if (qd_conn->policy_settings->maxSenders) {
        if (qd_conn->n_senders == qd_conn->policy_settings->maxSenders) {
            // Max sender limit specified and violated.
            qd_log(qd_conn->server->qd->policy->log_source, QD_LOG_INFO,
                "DENY AMQP Attach sender for user '%s', host '%s', app '%s' based on maxSenders limit",
                qd_conn->user_id, hostip, app);
            _qd_policy_deny_amqp_sender_link(pn_link, qd_conn);
            return false;
        } else {
            // max sender limit not violated
        }
    } else {
        // max sender limit not specified
    }
    // Approve sender link based on target
    const char * target = pn_terminus_get_address(pn_link_remote_target(pn_link));
    bool lookup;
    if (target && *target) {
        // a target is specified
        lookup = _qd_policy_approve_link_name(qd_conn->user_id, qd_conn->policy_settings->targets, target);

        qd_log(qd_conn->server->qd->policy->log_source, (lookup ? QD_LOG_TRACE : QD_LOG_INFO),
            "%s AMQP Attach sender link '%s' for user '%s', host '%s', app '%s' based on link target name",
            (lookup ? "ALLOW" : "DENY"), target, qd_conn->user_id, hostip, app);

        if (!lookup) {
            _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
            return false;
        }
    } else {
        // A sender with no remote target.
        // This happens all the time with anonymous relay
        lookup = qd_conn->policy_settings->allowAnonymousSender;
        qd_log(qd_conn->server->qd->policy->log_source, (lookup ? QD_LOG_TRACE : QD_LOG_INFO),
            "%s AMQP Attach anonymous sender for user '%s', host '%s', app '%s'",
            (lookup ? "ALLOW" : "DENY"), qd_conn->user_id, hostip, app);
        if (!lookup) {
            _qd_policy_deny_amqp_receiver_link(pn_link, qd_conn);
            return false;
        }
    }
    // Approved
    return true;
}
Esempio n. 7
0
static int handler(void *handler_context, void *conn_context, qd_conn_event_t event, qd_connection_t *qd_conn)
{
    qd_container_t  *container = (qd_container_t*) handler_context;
    pn_connection_t *conn      = qd_connection_pn(qd_conn);

    switch (event) {
    case QD_CONN_EVENT_LISTENER_OPEN:
        open_handler(container, qd_conn, QD_INCOMING, conn_context);
        return 1;

    case QD_CONN_EVENT_CONNECTOR_OPEN:
        open_handler(container, qd_conn, QD_OUTGOING, conn_context);
        return 1;

    case QD_CONN_EVENT_CLOSE:
        return close_handler(container, conn_context, conn, qd_conn);

    case QD_CONN_EVENT_WRITABLE:
        return writable_handler(container, conn, qd_conn);
    }

    return 0;
}
Esempio n. 8
0
int pn_event_handler(void *handler_context, void *conn_context, pn_event_t *event, qd_connection_t *qd_conn)
{
    qd_container_t  *container = (qd_container_t*) handler_context;
    pn_connection_t *conn      = qd_connection_pn(qd_conn);
    pn_session_t    *ssn;
    pn_link_t       *pn_link;
    qd_link_t       *qd_link;
    pn_delivery_t   *delivery;

    switch (pn_event_type(event)) {
    case PN_CONNECTION_REMOTE_OPEN :
        qd_connection_set_user(qd_conn);
        if (pn_connection_state(conn) & PN_LOCAL_UNINIT) {
            // This Open is an externally initiated connection
            // Let policy engine decide
            qd_connection_set_event_stall(qd_conn, true);
            qd_conn->open_container = (void *)container;
            qd_connection_invoke_deferred(qd_conn, qd_policy_amqp_open, qd_conn);
        } else {
            // This Open is in response to an internally initiated connection
            notify_opened(container, qd_conn, conn_context);
        }
        break;

    case PN_CONNECTION_REMOTE_CLOSE :
        if (pn_connection_state(conn) == (PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED))
            pn_connection_close(conn);
        break;

    case PN_SESSION_REMOTE_OPEN :
        if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
            ssn = pn_event_session(event);
            if (pn_session_state(ssn) & PN_LOCAL_UNINIT) {
                if (qd_conn->policy_settings) {
                    if (!qd_policy_approve_amqp_session(ssn, qd_conn)) {
                        break;
                    }
                    qd_conn->n_sessions++;
                }
                qd_policy_apply_session_settings(ssn, qd_conn);
                pn_session_open(ssn);
            }
        }
        break;

    case PN_SESSION_REMOTE_CLOSE :
        if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
            ssn = pn_event_session(event);
            if (pn_session_state(ssn) == (PN_LOCAL_ACTIVE | PN_REMOTE_CLOSED)) {
                // remote has nuked our session.  Check for any links that were
                // left open and forcibly detach them, since no detaches will
                // arrive on this session.
                pn_connection_t *conn = pn_session_connection(ssn);
                pn_link_t *pn_link = pn_link_head(conn, PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE);
                while (pn_link) {
                    if (pn_link_session(pn_link) == ssn) {
                        qd_link_t *qd_link = (qd_link_t*) pn_link_get_context(pn_link);
                        if (qd_link && qd_link->node) {
                            if (qd_conn->policy_settings) {
                                if (qd_link->direction == QD_OUTGOING) {
                                    qd_conn->n_receivers--;
                                    assert(qd_conn->n_receivers >= 0);
                                } else {
                                    qd_conn->n_senders--;
                                    assert(qd_conn->n_senders >= 0);
                                }
                            }
                            qd_log(container->log_source, QD_LOG_NOTICE,
                                   "Aborting link '%s' due to parent session end",
                                   pn_link_name(pn_link));
                            qd_link->node->ntype->link_detach_handler(qd_link->node->context,
                                                                      qd_link, QD_LOST);
                        }
                    }
                    pn_link = pn_link_next(pn_link, PN_LOCAL_ACTIVE | PN_REMOTE_ACTIVE);
                }
                if (qd_conn->policy_settings) {
                    qd_conn->n_sessions--;
                }
                pn_session_close(ssn);
            }
        }
        break;

    case PN_LINK_REMOTE_OPEN :
        if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
            pn_link = pn_event_link(event);
            if (pn_link_state(pn_link) & PN_LOCAL_UNINIT) {
                if (pn_link_is_sender(pn_link)) {
                    if (qd_conn->policy_settings) {
                        if (!qd_policy_approve_amqp_receiver_link(pn_link, qd_conn)) {
                            break;
                        }
                        qd_conn->n_receivers++;
                    }
                    setup_outgoing_link(container, pn_link);
                } else {
                    if (qd_conn->policy_settings) {
                        if (!qd_policy_approve_amqp_sender_link(pn_link, qd_conn)) {
                            break;
                        }
                        qd_conn->n_senders++;
                    }
                    setup_incoming_link(container, pn_link);
                }
            } else if (pn_link_state(pn_link) & PN_LOCAL_ACTIVE)
                handle_link_open(container, pn_link);
        }
        break;

    case PN_LINK_REMOTE_CLOSE :
    case PN_LINK_REMOTE_DETACH :
        if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) {
            pn_link = pn_event_link(event);
            qd_link = (qd_link_t*) pn_link_get_context(pn_link);
            if (qd_link) {
                qd_node_t *node = qd_link->node;
                qd_detach_type_t dt = pn_event_type(event) == PN_LINK_REMOTE_CLOSE ? QD_CLOSED : QD_DETACHED;
                if (node)
                    node->ntype->link_detach_handler(node->context, qd_link, dt);
                else if (qd_link->pn_link == pn_link) {
                    pn_link_close(pn_link);
                }
                if (qd_conn->policy_counted && qd_conn->policy_settings) {
                    if (pn_link_is_sender(pn_link)) {
                        qd_conn->n_receivers--;
                        qd_log(container->log_source, QD_LOG_TRACE,
                               "Closed receiver link %s. n_receivers: %d",
                               pn_link_name(pn_link), qd_conn->n_receivers);
                        assert (qd_conn->n_receivers >= 0);
                    } else {
                        qd_conn->n_senders--;
                        qd_log(container->log_source, QD_LOG_TRACE,
                               "Closed sender link %s. n_senders: %d",
                               pn_link_name(pn_link), qd_conn->n_senders);
                        assert (qd_conn->n_senders >= 0);
                    }
                }
                if (qd_link->close_sess_with_link && qd_link->pn_sess &&
                    pn_link_state(pn_link) == (PN_LOCAL_CLOSED | PN_REMOTE_CLOSED))
                    pn_session_close(qd_link->pn_sess);
            }
        }
        break;

    case PN_LINK_FLOW :
        pn_link = pn_event_link(event);
        qd_link = (qd_link_t*) pn_link_get_context(pn_link);
        if (qd_link && qd_link->node && qd_link->node->ntype->link_flow_handler)
            qd_link->node->ntype->link_flow_handler(qd_link->node->context, qd_link);
        break;

    case PN_DELIVERY :
        delivery = pn_event_delivery(event);
        if (pn_delivery_readable(delivery))
            do_receive(delivery);

        if (pn_delivery_updated(delivery)) {
            do_updated(delivery);
            pn_delivery_clear(delivery);
        }
        break;

    case PN_EVENT_NONE :
    case PN_REACTOR_INIT :
    case PN_REACTOR_QUIESCED :
    case PN_REACTOR_FINAL :
    case PN_TIMER_TASK :
    case PN_CONNECTION_INIT :
    case PN_CONNECTION_BOUND :
    case PN_CONNECTION_UNBOUND :
    case PN_CONNECTION_LOCAL_OPEN :
    case PN_CONNECTION_LOCAL_CLOSE :
    case PN_CONNECTION_FINAL :
    case PN_SESSION_INIT :
    case PN_SESSION_LOCAL_OPEN :
    case PN_SESSION_LOCAL_CLOSE :
    case PN_SESSION_FINAL :
    case PN_LINK_INIT :
    case PN_LINK_LOCAL_OPEN :
    case PN_LINK_LOCAL_CLOSE :
    case PN_LINK_LOCAL_DETACH :
    case PN_LINK_FINAL :
    case PN_TRANSPORT :
    case PN_TRANSPORT_ERROR :
    case PN_TRANSPORT_HEAD_CLOSED :
    case PN_TRANSPORT_TAIL_CLOSED :
    case PN_TRANSPORT_CLOSED :
    case PN_TRANSPORT_AUTHENTICATED :
    case PN_SELECTABLE_INIT :
    case PN_SELECTABLE_UPDATED :
    case PN_SELECTABLE_READABLE :
    case PN_SELECTABLE_WRITABLE :
    case PN_SELECTABLE_ERROR :
    case PN_SELECTABLE_EXPIRED :
    case PN_SELECTABLE_FINAL :
        break;
    }

    return 1;
}