Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers snmp_agent_dispatch.c Source File

snmp_agent_dispatch.c

Go to the documentation of this file.
00001 /**
00002  * @file snmp_agent_dispatch.c
00003  * @brief SNMP message dispatching
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This file is part of CycloneTCP Open.
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00024  *
00025  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00026  * @version 1.7.6
00027  **/
00028 
00029 //Switch to the appropriate trace level
00030 #define TRACE_LEVEL SNMP_TRACE_LEVEL
00031 
00032 //Dependencies
00033 #include "core/net.h"
00034 #include "snmp/snmp_agent.h"
00035 #include "snmp/snmp_agent_dispatch.h"
00036 #include "snmp/snmp_agent_pdu.h"
00037 #include "snmp/snmp_agent_misc.h"
00038 #include "mibs/mib2_module.h"
00039 #include "crypto.h"
00040 #include "asn1.h"
00041 #include "oid.h"
00042 #include "debug.h"
00043 
00044 //Check TCP/IP stack configuration
00045 #if (SNMP_AGENT_SUPPORT == ENABLED)
00046 
00047 
00048 /**
00049  * @brief Process incoming SNMP message
00050  * @param[in] context Pointer to the SNMP agent context
00051  * @return Error code
00052  **/
00053 
00054 error_t snmpProcessMessage(SnmpAgentContext *context)
00055 {
00056    error_t error;
00057 
00058    //Total number of messages delivered to the SNMP entity from the
00059    //transport service
00060    MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInPkts, 1);
00061 
00062    //Refresh SNMP engine time
00063    snmpRefreshEngineTime(context);
00064 
00065    //Message parsing initialization
00066    snmpInitMessage(&context->request);
00067 
00068    //Parse SNMP message header
00069    error = snmpParseMessageHeader(&context->request);
00070    //Any error to report?
00071    if(error)
00072       return error;
00073 
00074    //The SNMP agent verifies the version number. If there is a mismatch,
00075    //it discards the datagram and performs no further actions
00076    if(context->request.version < context->settings.versionMin ||
00077       context->request.version > context->settings.versionMax)
00078    {
00079       //Debug message
00080       TRACE_WARNING("  Invalid SNMP version!\r\n");
00081       //Discard incoming SNMP message
00082       return ERROR_INVALID_VERSION;
00083    }
00084 
00085 #if (SNMP_V1_SUPPORT == ENABLED)
00086    //SNMPv1 version?
00087    if(context->request.version == SNMP_VERSION_1)
00088    {
00089       //Process incoming SNMPv1 message
00090       error = snmpv1ProcessMessage(context);
00091    }
00092    else
00093 #endif
00094 #if (SNMP_V2C_SUPPORT == ENABLED)
00095    //SNMPv2c version?
00096    if(context->request.version == SNMP_VERSION_2C)
00097    {
00098       //Process incoming SNMPv2c message
00099       error = snmpv2cProcessMessage(context);
00100    }
00101    else
00102 #endif
00103 #if (SNMP_V3_SUPPORT == ENABLED)
00104    //SNMPv3 version?
00105    if(context->request.version == SNMP_VERSION_3)
00106    {
00107       //Process incoming SNMPv3 message
00108       error = snmpv3ProcessMessage(context);
00109    }
00110    else
00111 #endif
00112    //Invalid SNMP version?
00113    {
00114       //Debug message
00115       TRACE_WARNING("  Invalid SNMP version!\r\n");
00116 
00117       //Total number of SNMP messages which were delivered to the SNMP
00118       //protocol entity and were for an unsupported SNMP version
00119       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadVersions, 1);
00120 
00121       //Discard incoming SNMP message
00122       error = ERROR_INVALID_VERSION;
00123    }
00124 
00125    //Check status code
00126    if(error == NO_ERROR)
00127    {
00128       //Total number of messages which were passed from the SNMP protocol
00129       //entity to the transport service
00130       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpOutPkts, 1);
00131    }
00132    else if(error == ERROR_INVALID_TAG)
00133    {
00134       //Total number of ASN.1 or BER errors encountered by the SNMP protocol
00135       //entity when decoding received SNMP messages
00136       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInASNParseErrs, 1);
00137    }
00138 
00139    //Return status code
00140    return error;
00141 }
00142 
00143 
00144 /**
00145  * @brief Process incoming SNMPv1 message
00146  * @param[in] context Pointer to the SNMP agent context
00147  * @return Error code
00148  **/
00149 
00150 error_t snmpv1ProcessMessage(SnmpAgentContext *context)
00151 {
00152    error_t error;
00153 
00154 #if (SNMP_V1_SUPPORT == ENABLED)
00155    //Parse community name
00156    error = snmpParseCommunity(&context->request);
00157    //Any error to report?
00158    if(error)
00159       return error;
00160 
00161    //Information about the community name is extracted from the local
00162    //configuration datastore
00163    context->user = snmpFindUser(context, context->request.community,
00164       context->request.communityLen);
00165 
00166    //Invalid community name?
00167    if(context->user == NULL)
00168    {
00169       //Debug message
00170       TRACE_WARNING("  Invalid community name!\r\n");
00171 
00172       //Total number of SNMP messages delivered to the SNMP protocol entity
00173       //which used a SNMP community name not known to said entity
00174       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityNames, 1);
00175 
00176       //Report an error
00177       return ERROR_UNKNOWN_USER_NAME;
00178    }
00179 
00180    //Process PDU
00181    error = snmpProcessPdu(context);
00182    //Any error to report?
00183    if(error)
00184       return error;
00185 
00186    //Format SNMP message header
00187    error = snmpWriteMessageHeader(&context->response);
00188 #else
00189    //Report an error
00190    error = ERROR_INVALID_VERSION;
00191 #endif
00192 
00193    //Return status code
00194    return error;
00195 }
00196 
00197 
00198 /**
00199  * @brief Process incoming SNMPv2c message
00200  * @param[in] context Pointer to the SNMP agent context
00201  * @return Error code
00202  **/
00203 
00204 error_t snmpv2cProcessMessage(SnmpAgentContext *context)
00205 {
00206    error_t error;
00207 
00208 #if (SNMP_V2C_SUPPORT == ENABLED)
00209    //Parse community name
00210    error = snmpParseCommunity(&context->request);
00211    //Any error to report?
00212    if(error)
00213       return error;
00214 
00215    //Information about the community name is extracted from the local
00216    //configuration datastore
00217    context->user = snmpFindUser(context, context->request.community,
00218       context->request.communityLen);
00219 
00220    //Invalid community name?
00221    if(context->user == NULL)
00222    {
00223       //Debug message
00224       TRACE_WARNING("  Invalid community name!\r\n");
00225 
00226       //Total number of SNMP messages delivered to the SNMP protocol entity
00227       //which used a SNMP community name not known to said entity
00228       MIB2_INC_COUNTER32(mib2Base.snmpGroup.snmpInBadCommunityNames, 1);
00229 
00230       //Report an error
00231       return ERROR_UNKNOWN_USER_NAME;
00232    }
00233 
00234    //Process PDU
00235    error = snmpProcessPdu(context);
00236    //Any error to report?
00237    if(error)
00238       return error;
00239 
00240    //Format SNMP message header
00241    error = snmpWriteMessageHeader(&context->response);
00242 #else
00243    //Report an error
00244    error = ERROR_INVALID_VERSION;
00245 #endif
00246 
00247    //Return status code
00248    return error;
00249 }
00250 
00251 
00252 /**
00253  * @brief Process incoming SNMPv3 message
00254  * @param[in] context Pointer to the SNMP agent context
00255  * @return Error code
00256  **/
00257 
00258 error_t snmpv3ProcessMessage(SnmpAgentContext *context)
00259 {
00260    error_t error;
00261 
00262 #if (SNMP_V3_SUPPORT == ENABLED)
00263    //Parse msgGlobalData field
00264    error = snmpParseGlobalData(&context->request);
00265    //Any error to report?
00266    if(error)
00267       return error;
00268 
00269    //Parse msgSecurityParameters field
00270    error = snmpParseSecurityParameters(&context->request);
00271    //Any error to report?
00272    if(error)
00273       return error;
00274 
00275    //Start of exception handling block
00276    do
00277    {
00278       //Information about the value of the msgUserName field is extracted
00279       //from the local configuration datastore
00280       context->user = snmpFindUser(context, context->request.msgUserName,
00281          context->request.msgUserNameLen);
00282 
00283       //Check security parameters
00284       error = snmpCheckSecurityParameters(context->user, &context->request,
00285          context->contextEngine, context->contextEngineLen);
00286       //Invalid security parameters?
00287       if(error)
00288          break;
00289 
00290       //Check whether the authFlag is set
00291       if(context->request.msgFlags & SNMP_MSG_FLAG_AUTH)
00292       {
00293          //Authenticate incoming SNMP message
00294          error = snmpAuthIncomingMessage(context->user, &context->request);
00295          //Data authentication failed?
00296          if(error)
00297             break;
00298 
00299          //Replay protection
00300          error = snmpCheckEngineTime(context, &context->request);
00301          //Message outside of the time window?
00302          if(error)
00303             break;
00304       }
00305 
00306       //Check whether the privFlag is set
00307       if(context->request.msgFlags & SNMP_MSG_FLAG_PRIV)
00308       {
00309          //Decrypt data
00310          error = snmpDecryptData(context->user, &context->request);
00311          //Data decryption failed?
00312          if(error)
00313             break;
00314       }
00315 
00316       //End of exception handling block
00317    } while(0);
00318 
00319    //Check error indication
00320    if(error == ERROR_UNSUPPORTED_SECURITY_LEVEL ||
00321       error == ERROR_NOT_IN_TIME_WINDOW ||
00322       error == ERROR_UNKNOWN_USER_NAME ||
00323       error == ERROR_UNKNOWN_ENGINE_ID ||
00324       error == ERROR_AUTHENTICATION_FAILED ||
00325       error == ERROR_DECRYPTION_FAILED)
00326    {
00327       //Report the error indication to the remote SNMP engine using a Report-PDU
00328       error = snmpFormatReportPdu(context, error);
00329       //Any error to report?
00330       if(error)
00331          return error;
00332    }
00333    else if(error == NO_ERROR)
00334    {
00335       //Parse scopedPDU
00336       error = snmpParseScopedPdu(&context->request);
00337       //Any error to report?
00338       if(error)
00339          return error;
00340 
00341       //Process PDU
00342       error = snmpProcessPdu(context);
00343       //Any error to report?
00344       if(error)
00345          return error;
00346    }
00347    else
00348    {
00349       //Stop processing
00350       return error;
00351    }
00352 
00353    //Format scopedPDU
00354    error = snmpWriteScopedPdu(&context->response);
00355    //Any error to report?
00356    if(error)
00357       return error;
00358 
00359    //Check whether the privFlag is set
00360    if(context->response.msgFlags & SNMP_MSG_FLAG_PRIV)
00361    {
00362       //Encrypt data
00363       error = snmpEncryptData(context->user, &context->response, &context->salt);
00364       //Any error to report?
00365       if(error)
00366          return error;
00367    }
00368 
00369    //Format SNMP message header
00370    error = snmpWriteMessageHeader(&context->response);
00371    //Any error to report?
00372    if(error)
00373       return error;
00374 
00375    //Check whether the authFlag is set
00376    if(context->response.msgFlags & SNMP_MSG_FLAG_AUTH)
00377    {
00378       //Authenticate outgoing SNMP message
00379       error = snmpAuthOutgoingMessage(context->user, &context->response);
00380       //Any error to report?
00381       if(error)
00382          return error;
00383    }
00384 #else
00385    //Report an error
00386    error = ERROR_INVALID_VERSION;
00387 #endif
00388 
00389    //Return status code
00390    return error;
00391 }
00392 
00393 #endif
00394