The MIMIC TELNET Protocol Module is an optional facility that enables a command line management interface to device simulations on top of the Telnet protocol (RFC 854, 855). This interface is used for Cisco IOS, JUNOS or TL/1 command simulation.
TELNET server support is made available in MIMIC as an optional dynamically loadable module. Starting with MIMIC 10.00, you can use the Protocol Wizard to install the Telnet module as part of the IOS Simulator. If you prefer to enable Telnet by hand, you need to do the following:
INFO - TELNET : Loaded protocol from < path-to-DLL > INFO - TELNET (IOS) v7.00 : Individual license #2345
Once TELNET is loaded, any agent instance configured to support the TELNET protocol will be able to act as a TELNET server.
If the TELNET module is enabled, then Agent->Add, Agent->Configure and Agent->Paste dialogs will display TELNET as an additional checkbox in the Advanced pane along with the SNMP protocols. On selecting the checkbox a new TELNET pane will appear.
This TELNET configuration pane lets the user configure the parameters for a TELNET session:
This optional parameter specifies the port at which the server will be listening. The default is the standard port 23.
This mandatory parameter specifies the rules that govern the TELNET sessions to this agent. The rule file is in scripts/telnet/, and in effect implements a command-line interface. Each rule consists of a regular expression that is matched against the typed request (command), and a response that is shown. For more complicated rules, a MIMICshell script can be run. A sample rule file is shipped as sample.rul. Details can be found below.
This optional parameter specifies the prompt to be displayed by the server. If not specified, a default prompt is shown.
This optional parameter specifies the paging prompt to be displayed by the server when a command output is longer than the terminal length. If not specified, a default paging prompt is shown.
This optional parameter specifies the user database. This database is used for login and access control. Details can be found below.
This optional parameter specifies the key mappings. This database is used for keyboard shortcuts. Details can be found below.
If the mandatory parameters are supplied, the agent will automatically execute a TELNET server upon starting. A message in the log of the form
INFO 11/28.09:53:42 - TELNET server started for agent 2
indicates that the Telnet simulation is running.
A few new commands and some enhanced old commands can be used from the MIMICShell to control the TELNET functionality. Here is a synopsis:
This command lets the user gather the self-defining list of arguments required and their particulars. The parameters are detailed above. A sample exchange for this command would be:
mimicsh> mimic protocol msg TELNET get args {{port} {Port} {integer} {} {optional} {23}} {{rule} {Rule File} {file} {scripts/telnet {{*.rul {Rule database files} {edit yes} {new yes}}} - both} {mandatory} {sample.rul}} {{prompt} {Prompt} {string} {} {optional} {}} {{paging_prompt} {Paging Prompt} {string} {} {optional} { --More--}} {{userdb} {User DB} {file} {scripts/telnet {{*.db {User database files} {edit yes} {new yes}}} - both} {optional} {sampleuser.db}} {{keymap} {Key Map File} {file} {scripts/telnet {{*.kmap {Key mapping files} {edit yes} {new yes}}} - both} {optional} {sample.kmap}}
This command lets the user look at the protocols currently configured on the agent. A sample exchange for this command would be:
mimicsh> mimic agent get protocol snmpv1,snmpv2c,TELNET
This command lets the user change the protocol setting for an agent. A sample exchange for this command would be:
mimicsh> mimic agent get protocol snmpv1 mimicsh> mimic agent set protocol snmpv1,TELNET mimicsh> mimic agent get protocol snmpv1,TELNET
This command lets the user get the current argument settings. A sample exchange for this command would be:
mimicsh> mimic agent protocol msg TELNET get config {port=23} {rule=sample.rul} {prompt=} {paging_prompt=} {userdb=sampleuser.db} {keymap=sample.kmap}
This command lets the user change the current argument settings of all TELNET sessions for an agent. A sample exchange for this command would be:
mimicsh> mimic agent protocol msg TELNET get config {port=23} {rule=sample.rul} {prompt=} {paging_prompt=} {userdb=sampleuser.db} {keymap=sample.kmap} mimicsh> mimic agent protocol msg TELNET set config {prompt=IOS>} mimicsh> mimic agent protocol msg TELNET get config {port=23} {rule=sample.rul} {prompt=IOS>} {paging_prompt=} {userdb=sampleuser.db} {keymap=sample.kmap}
This command lets the user change the TELNET tracing configuration for an agent. A sample exchange would be:
mimicsh> mimic agent assign 1 mimicsh> mimic agent protocol msg TELNET get trace 0 mimicsh> mimic agent protocol msg TELNET set trace 1 mimicsh> mimic agent protocol msg TELNET get trace 1and the log would show:
INFO - agent 1 trace enabled for TELNET INFO - TELNET [AGT=1]: server started INFO - TELNET[AGT=1,CON=2]: connection request from [10.1.120.142,41851] INFO - TELNET[AGT=1,CON=2]: sending 3 byte(s) data in pkt #1 pkt to [10.1.120.142,41851] INFO - FF FB 01 ... INFO - TELNET[AGT=1,CON=2]: sending 3 byte(s) data in pkt #2 pkt to [10.1.120.142,41851] INFO - FF FB 03 ... INFO - TELNET[AGT=1,CON=2]: sending 3 byte(s) data in pkt #3 pkt to [10.1.120.142,41851] INFO - FF FD 1F ... INFO - TELNET[AGT=1,CON=2]: received 18 byte(s) data in pkt #3 from [10.1.120.142,41851] INFO - FF FD 01 FF FD 03 FF FB 1F FF FA 1F ............ INFO - 00 50 00 18 FF F0 .P.... ...
Returns TELNET statistics information:
In order, the statistic values are:
A sample exchange for these commands would be:
mimicsh> mimic protocol msg TELNET get stats_hdr {{connect} {Connect}} {{disconnect} {Disconnect}} {{pktSnt} {PktsSent}} {{pktRcvd} {PktsRcvd}} {{request} {CmdRequest}} {{response} {Response}} {{norule} {No Matching Rule }} {{script_err} {Script Error}} mimicsh> mimic agent protocol msg TELNET get statistics 9032775 9032772 162591536 39691090 8960770 0 0 1123
Returns 1 if the TELNET server can accept connections otherwise 0.
Returns the rules data base file name.
Returns the user data base file name.
Returns the keymap file name.
Retrieves the user information from the user database: a list of configured user entries, each with its user-name, password flag (set to 1 for no password), list of groups and optional password in the following format
{ user-name1 0|1 {group-list1} [password1] } { user-name2 0|1 {group-list2} [password2] } ... ... { usern 0|1 {group listn} [passwordn] }
Retrieves the currently connected sessions in a list of connection identifiers that can be used with the mimic agent protocol msg TELNET connection commands.
foreach conn [mimic agent protocol msg TELNET server get connections] { mimic agent protocol msg TELNET connection logon $conn hidden "{}" mimic agent protocol msg TELNET connection request $conn syslog mimic agent protocol msg TELNET connection request $conn exit }
Changes the current logon, so that (hidden) commands for a different access mode can be run.
Executes the command as if it had been typed by the user. This is the way to execute asynchronous commands.
This command triggers the asynchronous signal event with the specified signal name. See below.
By default, the MIMIC TELNET server listens on all the IP addresses (aliases) that are configured for an agent before the TELNET service is started. While the agent is running, TELNET service can be enabled and disabled on an IP alias using the above commands.
This command returns 1 if the IP alias is enabled, else 0.
This command returns the list of enabled IP aliases for this Telnet server.
The rules database is a ASCII text file that is associated with a TELNET server instance, and defines the behavior of the Telnet simulation. The loader reads in the file and sources any Tcl scripts as needed. The contents of the file are used to initialize data structures that will then be used to return a response string (output) for a given request string (user input). In the absence of a match an error is returned.
The rules database is located in the scripts/telnet/ directory in the MIMIC directory hierarchy. Any custom Tcl scripts also need to be in this same directory.
NOTE: rules and script files are cached, and modifications to them will only be reloaded by the parser when the rule file modification time is newer than what is in the cache.
The rules database is made of a series of "rule" blocks. A typical rules database will look something like:
version = 5.10 rule = { request = ^show memory$ response = 10485760 bytes (10MB) } rule = { request = ^show processes$ mapping = tcl_proc response = custom_responses.mtcl:show_processes delay = 25 } rule = { request = ^config* mapping = tcl_proc response = custom_responses.mtcl:configure delay = 15 } rule = { request = ^(sh|sho|show)\s(clo|cloc|clock)+ mapping = tcl_expr response = clock format [clock seconds] -format "*%H:%M:%S %Z %a %b %d %Y\r\n" delay = 25 }
In addition special blocks called "event" can also be defined in this file. These events will be hooked to pre-defined events during the course of a TELNET session. e.g.
event = { request = connect mapping = tcl_expr response = set str "Welcome to MIMIC IOS simulation.\r\n" response = append str " Server: $gCurrentConnLocAddr, $gCurrentConnLocPort\r\n" response = mts_puts $gCurrentConnId $str }
A rule will match the request clause with a user command in one of 3 ways:
This matching is selected with the matching = regexp clause. It is also the default if no matching clause is present in the rule. For example, a rule containing
request = ^(sh|sho|show)\s(clo|cloc|clock)+with no other matching clauses will match any command that the user types in that starts with show clock, including any combination of abbreviations sh and sho, or clo and cloc.
This matching is selected with the matching = strcmp clause. This causes a straight string comparison between the command typed in by the user and the string in the request clause. For example, a rule containing
request = where matching = strcmpwill match only the command where. This is really just a shorter form of the regular expression
request = ^where$
This matching is selected with the matching = stricmp clause. This causes a case insensitive string comparison between the command typed in by the user and the string in the request clause.
The first rule in the file which matches the command will be used. Thus it is better to put more specific matches at the beginning, more general matches later in the rule file.
There are three distinct types of mappings between requests and responses that will be supported by the rules database. These are as follows :
In this form a match of the request string will result in a hardcoded response string to be returned. This is the default, if no mapping clause is provided in the rule.
This mapping is selected with the mapping = tcl_expr clause. In this form the regular expression is used to match the request string. A match will then result in execution of a specified Tcl expression. The resulting value is sent back as a response.
This mapping is selected with the mapping = tcl_proc clause. In this form the regular expression is used to match the request string. A match will then result in invocation of a specified Tcl procedure. The response string will specify the Tcl file to be sourced and the Tcl proc to be executed. The resulting return value is sent back as response.
If a pipe symbol is detected in the command line, the parser will try to match the command before the pipe (through the expressions in the rules file) and feed its output to the command matched after the pipe symbol, again through the rules in the rule file (where commands can be marked to be matched only on the right hand side with the
pipe = consumer
statement). The sample ios.rul shows this for the IOS include, exclude and begin commands. The default pipe symbol is |, which you can override as detailed below.
Any Tcl expression evaluated as well as any Tcl procedure invoked will have a predefined set of global variables passed to it which identify the current environment.
This variable holds the command completed and normalized (space separated) user request string which was received on behalf of the user or the name of the current event.
This variable holds the user request string as it was sent by the client (without normalization and command completion) or the name of the current event.
This variable holds the agent that the current server belongs to.
This variable holds the current server's identifier.
This variable holds the current connection's identifier.
This variable holds the current connection's local address.
This variable holds the current connection's local port.
This variable holds the current connection's peer address.
This variable holds the current connection's peer port.
This variable holds the current rules database name.
On return, this variable indicates to the command parser what to do after processing this matching rule. A return value of 1 skips to the next matching rule without returning the output result. A return value of 2 skips caching the rule. A return value of 3 skips processing of any pipe consumer commands.
An optional delay parameter can be associated with a "rule" block which allows a user to prescribe a certain latency for the response. This delay is in milliseconds. The user of the rules database (TELNET DLL) is responsible to use this parameter to simulate the latency.
This optional access parameter can be used to specify a list of users that have access to a matching "rule" block. If this list is empty or not specified then any user can access the rule. This parameter can be used to restrict access to privileged command sets.
A set of built-in MIMIC Telnet Simulator (MTS) commands prefixed by "mts_" allows the modeller to invoke the API supported by the TELNET module.
This command will allow the caller to close the connection identified by the conn-id parameter. This is useful for the user to map arbitrary keywords to close the current connection. e.g.
rule = { request = ^exit$|^logout$ mapping = tcl_expr response = mts_exit $gCurrentConnId }
This command will allow the caller to change the prompt for connection identified by conn-id parameter. e.g.
rule = { mapping = tcl_expr request = ^setprompt* response = eval mts_setprompt $gCurrentConnId [lrange $gCurrentRequest 1 end] }
This command will enable the caller to retrieve the prompt for connection identified by conn-id parameter.
This command will allow the caller to invoke the API of the user-login subsystem embedded in each server. The following sub-commands will be supported :
The MTS framework enables the user to configure the login subsystem through a configuration file. This subsystem can also be fine tuned on per connection basis using the following attributes.
This command enables the callers to fine tune the user-login subsystem to their need. The following attributes are supported
The callback procedure will be called by setting all the global variables mentioned above as well as these other global variables:
This command allows the caller to enter into a logon transaction. If the user and password is provided then the client is not prompted for any information. If password is not provided then it is prompted. If user and password are not provided then both are prompted in that order. On completion (SUCCESS|FAILURE) of the login attempt the optional Tcl procedure or expression is invoked if specified by "mts_logon set callback" command.
This command allows the caller to logoff as a particular user in the context of the specified connection.
This command lists the users that are logged in for the specified connection. The caller can parse this list to determine if appropriate logon has been done.
Example: Here is a typical usage:
event = { request = connect mapping = tcl_proc response = custom_responses.mtcl:on_connect } event = { request = idle mapping = tcl_expr response = mts_exit $::gCurrentConnId } rule = { request = enable mapping = tcl_expr response = mts_logon init $gCurrentConnId enable } rule = { request = ^config* mapping tcl_proc response = custom_responses.mtcl:config access = enable } proc on_connect {} { set ret_msg "Welcome to MIMIC IOS simulator" global gCurrentConnId mts_logon config callback logon_callback mts_logon init $gCurrentConnId return $ret_msg } proc logon_callback {} { if { [mts_logon list] == "" } { global gCurrentConnId mts_puts $gCurrentConnId "% Login invalid" mts_exit $gCurrentConnId } }
returns configured terminal length, default is 23.
sets the terminal length. Paging can be disabled by setting the length to 0.
This command inserts the key into the command buffer. If no argument, then the key sequence that triggered this command is inserted into the buffer. This behaviour is the default for all unmodified key bindings. With an argument the key sequence in the argument is inserted instead.
This command causes the parser to start parsing the command buffer.
This causes a new line to be echoed.
This removes the preceding character in the command buffer.
This moves the insertion point back one position. Once at the beginning of the line, the insertion point cannot be moved further.
This moves the insertion point forward one position. Once at the end of the line, the insertion point cannot be moved further.
This command combined with mts_key_rubout can be used to ignore a key.
This moves the insertion point to the beginning of the line.
This moves the insertion point to the end of the line.
This command removes the preceding word, ie. a sequence of non-blank characters delimited by blank spaces.
This command removes the preceding characters to the beginning of the line.
This command removes the following characters to the end of the line.
These commands control the command buffer. You can set a string, append a string, get and reset the buffer.
This command allows a user to pass in an incomplete command string and peek at the completed result if an unambigious resolution is possible. This behaviour is built into the rule-execution code by default.
This command allows the user to pass in an incomplete command string and list possible completion alternatives. This is tied into the "\t" hotkey currently.
This command allows the user to pass in a command string and list possible subcommands that would follow the same to the next level. This would be useful for writing dynamic help.
returns a TCL list of command strings in the history buffer. This is used for the show history IOS command.
return the previous/next command in the history buffer. They are usually tied to keys in the key mapping.
sets the history buffer length. If the new length is less than the number of commands stored in the history, the oldest commands are lost. See the IOS terminal history size command implementation for a use of this command.
inherits the history buffer from the calling user. This is used in the IOS enable logon callback handler to share history buffer in user EXEC and privileged EXEC modes.
The response string displayed in a Telnet session is manipulated by the response primitive in rules files. Normally, this response is static, in that it will be displayed with the string returned from a rule. The following commands dynamically manipulate the response buffer for more advanced control of the response string (eg. in callback routines).
Sets the response to the specified string.
Appends the specified string to the response.
Clears the response string.
Gets the response string.
Flushes the response string and displays it in the telnet session.
Synchronously display the string. This is independent of the response buffer.
The Telnet framework supports asynchronous event handling for advanced processing of rules.
When an event occurs, the event listener will execute the callback procedure registered for it. Events are executed one at a time in the order they are received.
The event callback is invoked with all the global variables that are passed to the original request (where the event was registered). Along with those global variables some additional global variables are also passed to the callback procedure. They are:
event id, generated by the system
Will be either DATA, TIMER or SIGNAL
gCurrentEventId will have a signal name for signal event, key or line for a data type event and time quantum for timer type events.
For a timer type event this variable will hold the time (in milliseconds since UCT) when the event occured.
For a data type event this variable will hold the data sent by the client. If the data has any embedded unprintable character then it will be converted into standard mimic format (\xff ff ff).
Currently, the following 2 built-in events are supported:
This event occurs when a connection is first established to the telnet server.
This event occurs when there is a idle timeout on the connection.
These commands register and deregister user-defined events:
This command allows the caller to register a timer event and an associated callback for the connection specified by conn-id. On successful registration it returns an event-id. The values of timer event-id are prefixed with "tim_". Each command request can have 10 outstanding timer event, which can be increased upto 500 through the max_timer_event variable in telnet.cfg. This command takes optional arguments that will be passed as argument list while invoking the callback procedure. When the registered time quantum msec expires, the timer event will be cleared and the callback will be invoked.
Timer event registration will result in an error when it exceeds the configured limit.
The returned event-id can be used to cancel the event.
This command allows the caller to register a callback procedure to be invoked when the client sends either a single character or a line of characters (delimited by "\r\n") for the connection identified by conn-id parameter. This command takes optional arguments that would be passed in to the callback procedure as argument list. The caller can have only one outstanding data event registration. The data event registration will be cancelled as soon as the data event occurs. This command return an event identifier on success. The event identifier is always prefixed with "dat_" to indicate that the event is a data event.
Attempting to register a data event will result in an error, when there is already an outstanding data event registration.
The returned event-id can be used to cancel the event.
This command allows the caller to register a signal using a case sensitive unique signal identifier signal-name and an associated callback. It returns a unique event-id prefixed with "sig_".
Signals are triggered either by scripts (action, completion, etc) or manually through the mimic shell using the "telnet" protocol command (defined above). The caller is allowed to register a maximum of 10 signals, which can be configured through the max_signal configurable in telnet.cfg. When a signal is triggered its registration will be cancelled and the associated callback procedure will be called with all the optional arguments as argument list.
Any attempt to register a signal with an outstanding (not yet triggered) signal name will result in error.
The returned event-id can be used to cancel the event.
This command cancels a pending event registration identified by event-id. An attempt to cancel an unregistered event results in error.
This command will return a TCL list of outstanding (not yet serviced) registered events in the following format:
{ { event_id1, type1, value1, callback1, {arg_list1} } , { event_id2, type2, value2 ,callback2, {arg_list2} } ..... ..... { event_idn, typen, valuen ,callbackn, {arg_listn} } }
The Connection Variable Store is a volatile data storage facility (similar to the MIMIC Variable Store) that resides within the context (or scope) of each connection and is active for the duration of its associated connection. Variables can be used to store connection-specific state without interfering with other connections. These variables are cleaned up when the connection is closed.
The Connection Variable Store facility can be accessed through the mts_store built-in command.
These commands allow the creation of a new variable var, or changing an existing variable, with the value val. The append sub-command will append the value val to an existing variable, or create a new one. The set sub-command will overwrite an existing variable, or create a new one.
Deletes a currently defined variable var.
Fetches the value associated with a variable var. The value will be returned as a string (like all Tcl values).
This command can be used as a predicate to ascertain the existence of a given variable var. It returns "1" if the variable exists, else "0".
This command will return the list of variables in the said scope. The list will be a Tcl format list with curly braces "{}" around each list element. These elements in turn are space separated.
The user database contains entries for each user that has access to the simulation. The username and password will be authenticated at login. In addition, each user belongs to one or more access groups, with which access to commands can be controlled (with the access parameter). Here is a sample file:
version = 5.20 user = { username = lab password = lab123 } user = { username = admin password = admin123 group = admin config } user = { username = enable password = enable123 group = enable }
The key mapping file defines keyboard shortcuts for commands or special functionality. Here is a sample file:
version = 5.40 keymap = { # IOS help hot key key = ? action = mts_key_insert action = mts_key_echo_newline action = mts_key_done } keymap = { # IOS command completion hot key key = \t action = mts_key_cmd_completion } keymap = { # up arrow key = \M-[A action = mts_key_get_prev_history } keymap = { # down arrow key = \M-[B action = mts_key_get_next_history }
NOTE: \r (0x0D) and \n (0x0A) have a built-in mapping that invokes a request rule execution action. Either the 0x0D byte or the 0x0A byte alone from the telnet client is sufficient to trigger the built-in action.
The optional Telnet configuration file config/telnet.cfg overrides some hard-coded parameters in the Telnet server. It is only necessary to customize some of the default prompts and error messages. Here is a sample:
# this is a sample telnet.cfg file to configure advanced options # port - Telnet server port (default 23) port=2323 # maximum simultaneous clients per agent (default 3) # this does not place a limit on the number of simultaneous clients, # but an upper limit on resources over all the agents. That upper limit # is max_agents * simultaneous_clients . #simultaneous_clients = 10 # tcp_nodelay - control TCP_NODELAY, ie. enable/disable Van Jacobson TCP/IP # optimizations (default is 1, ie. optimization off) # for small number of telnet sessions the default behavior achieves better # response time, at the cost of utilization #tcp_nodelay=1 #prompt= # rulesdb - default rules database #rulesdb=sample.rul # userdb - default user database #userdb=sampleuser.db login_prompt=Username: #password_prompt= # logon_failure_msg - error message on logon failure #logon_failure_msg= # noaccess_msg - error message on access failure #noaccess_msg=$r: Permission denied\r\n # ruleslookup_failure - error message on rules lookup failure #ruleslookup_failure_msg=$r: Command not found\r\n # echo - controls echoing: on (default), off, negotiated #echo=on # term_keymap_file - key handling in raw mode #term_keymap_file=tl1.kmap # pipe symbol(s) #pipe = |