예제 #1
0
/* Process the SPA packet data
*/
void
incoming_spa(fko_srv_options_t *opts)
{
    /* Always a good idea to initialize ctx to null if it will be used
     * repeatedly (especially when using fko_new_with_data()).
    */
    fko_ctx_t       ctx = NULL;

    char            *spa_ip_demark, *raw_digest = NULL;
    int             res, enc_type, stanza_num=0;
    int             added_replay_digest = 0;
    int             is_err, cmd_exec_success = 0, attempted_decrypt = 0;
    int             conf_pkt_age = 0;
    char            dump_buf[CTX_DUMP_BUFSIZE];

    spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);

    /* This will hold our pertinent SPA data.
    */
    spa_data_t spadat;

    /* Loop through all access stanzas looking for a match
    */
    acc_stanza_t        *acc = opts->acc_stanzas;

    inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
        spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));

    inet_ntop(AF_INET, &(spa_pkt->packet_dst_ip),
        spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip));

    /* At this point, we want to validate and (if needed) preprocess the
     * SPA data and/or to be reasonably sure we have a SPA packet (i.e
     * try to eliminate obvious non-spa packets).
    */
    if(!precheck_pkt(opts, spa_pkt, &spadat, &raw_digest))
        return;

    if(strncasecmp(opts->config[CONF_ENABLE_SPA_PACKET_AGING], "Y", 1) == 0)
    {
        conf_pkt_age = strtol_wrapper(opts->config[CONF_MAX_SPA_PACKET_AGE],
                0, RCHK_MAX_SPA_PACKET_AGE, NO_EXIT_UPON_ERR, &is_err);
        if(is_err != FKO_SUCCESS)
        {
            log_msg(LOG_ERR, "[*] [%s] invalid MAX_SPA_PACKET_AGE", spadat.pkt_source_ip);
            return;
        }
    }

    /* Now that we know there is a matching access.conf stanza and the
     * incoming SPA packet is not a replay, see if we should grant any
     * access
    */
    while(acc)
    {
        res = FKO_SUCCESS;
        cmd_exec_success  = 0;
        attempted_decrypt = 0;
        stanza_num++;

        /* Start access loop with a clean FKO context
        */
        if(ctx != NULL)
        {
            if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                    spadat.pkt_source_ip, stanza_num
                );
            ctx = NULL;
        }

        /* Check for a match for the SPA source and destination IP and the access stanza
        */
        if(! src_dst_check(acc, spa_pkt, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        log_msg(LOG_INFO, "(stanza #%d) SPA Packet from IP: %s received with access source match",
            stanza_num, spadat.pkt_source_ip);

        log_msg(LOG_DEBUG, "SPA Packet: '%s'", spa_pkt->packet_data);

        /* Make sure this access stanza has not expired
        */
        if(! check_stanza_expiration(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Get encryption type and try its decoding routine first (if the key
         * for that type is set)
        */
        enc_type = fko_encryption_type((char *)spa_pkt->packet_data);

        if(! handle_rijndael_enc(acc, spa_pkt, &spadat, &ctx,
                    &attempted_decrypt, &cmd_exec_success, enc_type,
                    stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        if(! handle_gpg_enc(acc, spa_pkt, &spadat, &ctx, &attempted_decrypt,
                    cmd_exec_success, enc_type, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        if(! check_mode_ctx(&spadat, &ctx, attempted_decrypt,
                    enc_type, stanza_num, res))
        {
            acc = acc->next;
            continue;
        }

        /* Add this SPA packet into the replay detection cache
        */
        if(! add_replay_cache(opts, acc, &spadat, raw_digest,
                    &added_replay_digest, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        /* At this point the SPA data is authenticated via the HMAC (if used
         * for now). Next we need to see if it meets our access criteria which
         * the server imposes regardless of the content of the SPA packet.
        */
        log_msg(LOG_DEBUG, "[%s] (stanza #%d) SPA Decode (res=%i):",
            spadat.pkt_source_ip, stanza_num, res);

        res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf));
        if (res == FKO_SUCCESS)
            log_msg(LOG_DEBUG, "%s", dump_buf);
        else
            log_msg(LOG_WARNING, "Unable to dump FKO context: %s", fko_errstr(res));

        /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
         * then we need to make sure this incoming message is signer ID matches
         * an entry in the list.
        */

        if(! handle_gpg_sigs(acc, &spadat, &ctx, enc_type, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        /* Populate our spa data struct for future reference.
        */
        res = get_spa_data_fields(ctx, &spadat);

        if(res != FKO_SUCCESS)
        {
            log_msg(LOG_ERR, "[%s] (stanza #%d) Unexpected error pulling SPA data from the context: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        /* Figure out what our timeout will be. If it is specified in the SPA
         * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
         * access.conf file (if there is one).  Otherwise use the default.
        */
        set_timeout(acc, &spadat);

        /* Check packet age if so configured.
        */
        if(! check_pkt_age(opts, &spadat, stanza_num, conf_pkt_age))
        {
            acc = acc->next;
            continue;
        }

        /* At this point, we have enough to check the embedded (or packet source)
         * IP address against the defined access rights.  We start by splitting
         * the spa msg source IP from the remainder of the message.
        */
        spa_ip_demark = strchr(spadat.spa_message, ',');
        if(spa_ip_demark == NULL)
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Error parsing SPA message string: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1
                || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN)
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num);
            break;
        }

        strlcpy(spadat.spa_message_src_ip,
            spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);

        if(! is_valid_ipv4_addr(spadat.spa_message_src_ip))
        {
            log_msg(LOG_WARNING, "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));
            break;
        }

        strlcpy(spadat.spa_message_remain, spa_ip_demark+1, MAX_DECRYPTED_SPA_LEN);

        /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
         * is allowed.
        */
        if(! check_src_access(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
         * matches.
        */
        if(! check_username(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Take action based on SPA message type.
        */
        if(! check_nat_access_types(opts, acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Command messages.
        */
        if(spadat.message_type == FKO_COMMAND_MSG)
        {
            if(process_cmd_msg(opts, acc, &spadat, stanza_num, &res))
            {
                /* we processed the command on a matching access stanza, so we
                 * don't look for anything else to do with this SPA packet
                */
                break;
            }
            else
            {
                acc = acc->next;
                continue;
            }
        }

        /* From this point forward, we have some kind of access message. So
         * we first see if access is allowed by checking access against
         * restrict_ports and open_ports.
         *
         *  --DSS TODO: We should add BLACKLIST support here as well.
        */
        if(! check_port_proto(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* At this point, we process the SPA request and break out of the
         * access stanza loop (first valid access stanza stops us looking
         * for others).
        */
        if(opts->test)  /* no firewall changes in --test mode */
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) --test mode enabled, skipping firewall manipulation.",
                spadat.pkt_source_ip, stanza_num
            );
            acc = acc->next;
            continue;
        }
        else
        {
            process_spa_request(opts, acc, &spadat);
        }

        /* If we made it here, then the SPA packet was processed according
         * to a matching access.conf stanza, so we're done with this packet.
        */
        break;
    }

    if (raw_digest != NULL)
        free(raw_digest);

    if(ctx != NULL)
    {
        if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                spadat.pkt_source_ip, stanza_num
            );
        ctx = NULL;
    }

    return;
}
예제 #2
0
/* Process the SPA packet data
*/
void
incoming_spa(fko_srv_options_t *opts)
{
    /* Always a good idea to initialize ctx to null if it will be used
     * repeatedly (especially when using fko_new_with_data()).
    */
    fko_ctx_t       ctx = NULL;

    char            *spa_ip_demark, *raw_digest = NULL;
    int             res, enc_type, stanza_num=0;
    int             added_replay_digest = 0;
    int             cmd_exec_success = 0, attempted_decrypt = 0;
    char            dump_buf[CTX_DUMP_BUFSIZE];

    spa_pkt_info_t *spa_pkt = &(opts->spa_pkt);

    /* This will hold our pertinent SPA data.
    */
    spa_data_t spadat;

    /* Loop through all access stanzas looking for a match
    */
    //²éÕÒËùÓеÄstanzas£¬Æ¥ÅäÏàÓ¦Ïî¡£
    acc_stanza_t        *acc = opts->acc_stanzas;

    inet_ntop(AF_INET, &(spa_pkt->packet_src_ip),
        spadat.pkt_source_ip, sizeof(spadat.pkt_source_ip));	//»ñÈ¡Êý¾Ý±¨À´Ô´µØÖ·¡£

    inet_ntop(AF_INET, &(spa_pkt->packet_dst_ip),
        spadat.pkt_destination_ip, sizeof(spadat.pkt_destination_ip));	//»ñÈ¡Êý¾Ý±¨Ä¿µÄµØÖ·¡£

    /* At this point, we want to validate and (if needed) preprocess the
     * SPA data and/or to be reasonably sure we have a SPA packet (i.e
     * try to eliminate obvious non-spa packets).
    */
    //ÔÚÕâÀÎÒÃÇÒªÑéÖ¤ºÍÔ¤´¦ÀíSPAÊý¾Ý£¬ÌÞ³ýÃ÷ÏÔ²»ÊÇSPAµÄÊý¾Ý°ü¡£
    //ͨ¹ý±È¶ÔÕªÒª¼ì²éÊý¾ÝÍêÕûÐÔºÍÊÇ·ñÊܵ½ÖطŹ¥»÷¡£
    //¼ÆËãctx->encrypted_msgµÄSHA256ÕªÒªÊý¾Ý£¬´æÔÚraw_digest¡£
    if(!precheck_pkt(opts, spa_pkt, &spadat, &raw_digest))
        return;

    /* Now that we know there is a matching access.conf stanza and the
     * incoming SPA packet is not a replay, see if we should grant any
     * access
    */
    while(acc)
    {
        res = FKO_SUCCESS;
        cmd_exec_success  = 0;
        attempted_decrypt = 0;
        stanza_num++;

        /* Start access loop with a clean FKO context
        */
        //¶Ôÿһ¸östanza½øÐÐÆ¥Å䣬ֱµ½Æ¥Åä³É¹¦ÎªÖ¹¡£
        if(ctx != NULL)
        {
            if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
                log_msg(LOG_WARNING,
                    "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                    spadat.pkt_source_ip, stanza_num
                );
            ctx = NULL;
        }

        /* Check for a match for the SPA source and destination IP and the access stanza
        */
        //Æ¥ÅästanzaÖеÄÔ´µØÖ·ºÍÄ¿µÄµØÖ·¡£
        if(! src_dst_check(acc, spa_pkt, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        log_msg(LOG_INFO,
            "(stanza #%d) SPA Packet from IP: %s received with access source match",
            stanza_num, spadat.pkt_source_ip);

        log_msg(LOG_DEBUG, "SPA Packet: '%s'", spa_pkt->packet_data);

        /* Make sure this access stanza has not expired
        */
        //È·±£Õâ¸östanzaûÓйýÆÚ¡£
        if(! check_stanza_expiration(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Get encryption type and try its decoding routine first (if the key
         * for that type is set)
        */
        //¼ì²â´Ë¶ÎÃÜÎĵļÓÃÜÀàÐÍ¡£
        enc_type = fko_encryption_type((char *)spa_pkt->packet_data);

		//»¹Ô­¼ÓÑÎÃÜÎÄ£¬Í¨¹ýHMACժҪУÑéÊý¾Ý°üµÄÍêÕûÐÔ£¬½âÃÜencrypted_msg¡£
        if(acc->use_rijndael)
            handle_rijndael_enc(acc, spa_pkt, &spadat, &ctx,
                        &attempted_decrypt, &cmd_exec_success, enc_type,
                        stanza_num, &res);

        if(! handle_gpg_enc(acc, spa_pkt, &spadat, &ctx, &attempted_decrypt,
                    cmd_exec_success, enc_type, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        if(! check_mode_ctx(&spadat, &ctx, attempted_decrypt,
                    enc_type, stanza_num, res))
        {
            acc = acc->next;
            continue;
        }

        /* Add this SPA packet into the replay detection cache
        */
        //¼ì²âÖطŹ¥»÷¡£
        if(! add_replay_cache(opts, acc, &spadat, raw_digest,
                    &added_replay_digest, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        /* At this point the SPA data is authenticated via the HMAC (if used
         * for now). Next we need to see if it meets our access criteria which
         * the server imposes regardless of the content of the SPA packet.
        */
        log_msg(LOG_DEBUG, "[%s] (stanza #%d) SPA Decode (res=%i):",
            spadat.pkt_source_ip, stanza_num, res);

        res = dump_ctx_to_buffer(ctx, dump_buf, sizeof(dump_buf));
        if (res == FKO_SUCCESS)
            log_msg(LOG_DEBUG, "%s", dump_buf);
        else
            log_msg(LOG_WARNING, "Unable to dump FKO context: %s", fko_errstr(res));

        /* First, if this is a GPG message, and GPG_REMOTE_ID list is not empty,
         * then we need to make sure this incoming message is signer ID matches
         * an entry in the list.
        */

        if(! handle_gpg_sigs(acc, &spadat, &ctx, enc_type, stanza_num, &res))
        {
            acc = acc->next;
            continue;
        }

        /* Populate our spa data struct for future reference.
        */
        //ÏòspadatÖÐÌî³ä×ֶΡ£
        res = get_spa_data_fields(ctx, &spadat);

        if(res != FKO_SUCCESS)
        {
            log_msg(LOG_ERR,
                "[%s] (stanza #%d) Unexpected error pulling SPA data from the context: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        /* Figure out what our timeout will be. If it is specified in the SPA
         * data, then use that.  If not, try the FW_ACCESS_TIMEOUT from the
         * access.conf file (if there is one).  Otherwise use the default.
        */
        //²é¿´ÔÚSPAÖÐÓÐûÓÐÉèÖó¬Ê±×ֶΣ¬·ñÔò¾ÍÓÃaccess.confÖÐÉèÖõÄ×ֶΡ£
        set_timeout(acc, &spadat);

        /* Check packet age if so configured.
        */
        //²é¿´Êý¾Ý°üÖеÄʱ¼ä´ÁÊÇ·ñ¹ýʱ¡£
        if(! check_pkt_age(opts, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* At this point, we have enough to check the embedded (or packet source)
         * IP address against the defined access rights.  We start by splitting
         * the spa msg source IP from the remainder of the message.
        */
        spa_ip_demark = strchr(spadat.spa_message, ',');
        if(spa_ip_demark == NULL)
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) Error parsing SPA message string: %s",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));

            acc = acc->next;
            continue;
        }

        if((spa_ip_demark-spadat.spa_message) < MIN_IPV4_STR_LEN-1
                || (spa_ip_demark-spadat.spa_message) > MAX_IPV4_STR_LEN)
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num);
            break;
        }

        strlcpy(spadat.spa_message_src_ip,
            spadat.spa_message, (spa_ip_demark-spadat.spa_message)+1);

        if(! is_valid_ipv4_addr(spadat.spa_message_src_ip))
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) Invalid source IP in SPA message, ignoring SPA packet",
                spadat.pkt_source_ip, stanza_num, fko_errstr(res));
            break;
        }

        strlcpy(spadat.spa_message_remain, spa_ip_demark+1, MAX_DECRYPTED_SPA_LEN);

        /* If use source IP was requested (embedded IP of 0.0.0.0), make sure it
         * is allowed.
        */
        if(! check_src_access(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* If REQUIRE_USERNAME is set, make sure the username in this SPA data
         * matches.
        */
        //Èç¹ûREQUIRE_USERNAME ×ֶα»ÉèÖã¬È·±£Óû§ÃûÔÚSPAÖпɱ»Æ¥Åä¡£
        if(! check_username(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Take action based on SPA message type.
        */
        if(! check_nat_access_types(opts, acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* Command messages.
        */
        if(acc->cmd_cycle_open != NULL)
        {
            if(cmd_cycle_open(opts, acc, &spadat, stanza_num, &res))
                break; /* successfully processed a matching access stanza */
            else
            {
                acc = acc->next;
                continue;
            }
        }
        else if(spadat.message_type == FKO_COMMAND_MSG)
        {
            if(process_cmd_msg(opts, acc, &spadat, stanza_num, &res))
            {
                /* we processed the command on a matching access stanza, so we
                 * don't look for anything else to do with this SPA packet
                */
                break;
            }
            else
            {
                acc = acc->next;
                continue;
            }
        }

        /* From this point forward, we have some kind of access message. So
         * we first see if access is allowed by checking access against
         * restrict_ports and open_ports.
         *
         *  --DSS TODO: We should add BLACKLIST support here as well.
        */
        if(! check_port_proto(acc, &spadat, stanza_num))
        {
            acc = acc->next;
            continue;
        }

        /* At this point, we process the SPA request and break out of the
         * access stanza loop (first valid access stanza stops us looking
         * for others).
        */
        if(opts->test)  /* no firewall changes in --test mode */
        {
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) --test mode enabled, skipping firewall manipulation.",
                spadat.pkt_source_ip, stanza_num
            );
            acc = acc->next;
            continue;
        }
        else
        {
            if(acc->cmd_cycle_open != NULL)
            {
            		//Ö´ÐÐiptablesµÄCMD¡£
                if(cmd_cycle_open(opts, acc, &spadat, stanza_num, &res))
                    break; /* successfully processed a matching access stanza */
                else
                {
                    acc = acc->next;
                    continue;
                }
            }
            else
            {
                process_spa_request(opts, acc, &spadat);
            }
        }

        /* If we made it here, then the SPA packet was processed according
         * to a matching access.conf stanza, so we're done with this packet.
        */
        break;
    }

    if (raw_digest != NULL)
        free(raw_digest);

    if(ctx != NULL)
    {
        if(fko_destroy(ctx) == FKO_ERROR_ZERO_OUT_DATA)
            log_msg(LOG_WARNING,
                "[%s] (stanza #%d) fko_destroy() could not zero out sensitive data buffer.",
                spadat.pkt_source_ip, stanza_num
            );
        ctx = NULL;
    }

    return;
}